bumped linux to latest Funkey_S with integrated patches

Signed-off-by: Michel-FK <michel.stempin@funkey-project.com>
This commit is contained in:
Michel-FK 2020-10-18 13:03:02 +02:00
parent a8e82b4b55
commit 2f7ee632e0
30 changed files with 1 additions and 43806 deletions

View File

@ -1,74 +0,0 @@
fb_st7789v.c | 34 ++++++++++++++++++++++++++++++++--
1 file changed, 32 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/fbtft/fb_st7789v.c b/drivers/staging/fbtft/fb_st7789v.c
index a5d7c87..69f52af 100644
--- a/drivers/staging/fbtft/fb_st7789v.c
+++ b/drivers/staging/fbtft/fb_st7789v.c
@@ -86,6 +86,28 @@ enum st7789v_command {
static int init_display(struct fbtft_par *par)
{
/* turn off sleep mode */
+ /*write_reg(par, 0x11);
+ mdelay(120);
+
+ write_reg(par, 0x36, 0x00);
+ write_reg(par, 0x3A, 0x05);
+
+ write_reg(par, 0xB2,0x0C,0x0C,0x00,0x33,0x33);
+ write_reg(par, 0xB7,0x35);
+ write_reg(par, 0xBB,0x1A);
+ write_reg(par, 0xC0,0x2C);
+ write_reg(par, 0xC2,0x01);
+ write_reg(par, 0xC3,0x0B);
+ write_reg(par, 0xC4,0x20);
+ write_reg(par, 0xC6,0x0F);
+ write_reg(par, 0xD0,0xA4,0xA1);
+ write_reg(par, 0x21);
+ write_reg(par, 0xE0,0x00,0x19,0x1E,0x0A,0x09,0x15,0x3D,0x44,0x51,0x12,0x03,0x00,0x3F,0x3F);
+ write_reg(par, 0xE1,0x00,0x18,0x1E,0x0A,0x09,0x25,0x3F,0x43,0x52,0x33,0x03,0x00,0x3F,0x3F);
+ write_reg(par, 0x29);*/
+
+
+ /* turn off sleep mode */
write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE);
mdelay(120);
@@ -128,7 +150,14 @@ static int init_display(struct fbtft_par *par)
*/
write_reg(par, PWCTRL1, 0xA4, 0xA1);
+ /* Ystart at 80 , Yend at 240 */
+ write_reg(par, 0x2B, 0x00, 0x50, 0x00, 0xF0);
+
+ /* Display Inversion of colors */
+ write_reg(par, 0x21);
+
write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
+
return 0;
}
@@ -189,7 +218,7 @@ static int set_gamma(struct fbtft_par *par, u32 *curves)
* The masks are the same for both positive and negative voltage
* gamma curves.
*/
- static const u8 gamma_par_mask[] = {
+ const u8 gamma_par_mask[] = {
0xFF, /* V63[3:0], V0[3:0]*/
0x3F, /* V1[5:0] */
0x3F, /* V2[5:0] */
@@ -241,7 +270,7 @@ static int blank(struct fbtft_par *par, bool on)
static struct fbtft_display display = {
.regwidth = 8,
.width = 240,
- .height = 320,
+ .height = 240,
.gamma_num = 2,
.gamma_len = 14,
.gamma = DEFAULT_GAMMA,
@@ -263,3 +292,4 @@ MODULE_ALIAS("platform:st7789v");
MODULE_DESCRIPTION("FB driver for the ST7789V LCD Controller");
MODULE_AUTHOR("Dennis Menschel");
MODULE_LICENSE("GPL");
+

View File

@ -1,195 +0,0 @@
--- /dev/null 2019-05-04 09:53:55.553276856 +0200
+++ a/arch/arm/boot/dts/sun8i-v3s-funkey.dts 2019-05-04 20:06:53.118696800 +0200
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2019 Michel Stempin <michel.stempin@wanadoo.fr>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun8i-v3s.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+/ {
+ model = "FunKey";
+ compatible = "funkey", "allwinner,sun8i-v3s";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pwm 0 100000 1>;
+ brightness-levels = <0 1 2 3 8 14 21 32 46 60 80 100>; //2.2 div factor
+ default-brightness-level = <11>;
+ power-supply = <&reg_vcc5v0>;
+ };
+};
+
+&codec {
+ allwinner,audio-routing =
+ "Headphone", "HP",
+ "Headphone", "HPCOM",
+ "MIC1", "Mic",
+ "Mic", "HBIAS";
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+
+ /* axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupts = <0>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ }; */
+};
+
+&mmc0 {
+ pinctrl-0 = <&mmc0_pins_a>;
+ pinctrl-names = "default";
+ broken-cd;
+ bus-width = <4>;
+ vmmc-supply = <&reg_vcc3v3>;
+ vqmmc-supply = <&reg_vcc3v3>;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+/*
+#include "axp209.dtsi"
+
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu-sys-ephy";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3450000>;
+ regulator-name = "vcc-io-ephy-mcsi-usb";
+};
+
+&reg_ldo1 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3600000>;
+ regulator-name = "vcc-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "avcc-pll";
+};
+*/
+
+&reg_vcc3v0 {
+ regulator-always-on;
+ status = "okay";
+};
+
+&reg_vcc3v3 {
+ regulator-always-on;
+ status = "okay";
+};
+
+&reg_vcc5v0 {
+ regulator-always-on;
+ status = "okay";
+};
+
+&spi0 {
+ status = "okay";
+
+ st7789v@0 {
+ compatible = "sitronix,st7789v";
+ reg = <0>;
+ spi-max-frequency = <50000000>;
+ txbuflen = <115200>;
+ rotate = <0>;
+ fps = <50>;
+ buswidth = <8>;
+ reset-gpios = <&pio 1 2 GPIO_ACTIVE_HIGH>; //PB2
+ dc-gpios = <&pio 2 0 GPIO_ACTIVE_LOW>; //PC0 (MISO)
+ debug = <0>;
+ };
+};
+
+&uart0 {
+ pinctrl-0 = <&uart0_pins_a>;
+ pinctrl-names = "default";
+ status = "okay";
+};
+
+&pwm {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pins>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "peripheral";
+ status = "okay";
+};
+
+&usbphy {
+ usb0_vbus-supply = <&reg_vcc5v0>;
+ phy-supply = <&reg_vcc5v0>;
+ vcc = <&reg_vcc5v0>;
+ status = "okay";
+};

View File

@ -1,12 +0,0 @@
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 1f97ae8..e798bf1 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -932,6 +932,7 @@ dtb-$(CONFIG_MACH_SUN8I) += \
sun8i-h3-orangepi-plus2e.dtb \
sun8i-r16-bananapi-m2m.dtb \
sun8i-r16-parrot.dtb \
+ sun8i-v3s-funkey.dtb \
sun8i-v3s-licheepi-zero.dtb \
sun8i-v3s-licheepi-zero-dock.dtb \
sun8i-v3s-licheepi-zero-with-480x272-lcd.dtb \

View File

@ -1,69 +0,0 @@
diff --git a/arch/arm/boot/dts/sun8i-v3s-funkey.dts b/arch/arm/boot/dts/sun8i-v3s-funkey.dts
index 0a8ce5c0..31fddd2e 100644
--- a/arch/arm/boot/dts/sun8i-v3s-funkey.dts
+++ b/arch/arm/boot/dts/sun8i-v3s-funkey.dts
@@ -81,13 +81,14 @@
&i2c0 {
status = "okay";
- /* axp209: pmic@34 {
+ axp209: pmic@34 {
compatible = "x-powers,axp209";
reg = <0x34>;
- interrupts = <0>;
+ interrupt-parent = <&pio>;
+ interrupts = <1 5 IRQ_TYPE_EDGE_FALLING>;
interrupt-controller;
#interrupt-cells = <1>;
- }; */
+ };
};
&mmc0 {
@@ -104,9 +105,24 @@
status = "okay";
};
-/*
#include "axp209.dtsi"
+&ac_power_supply {
+ status = "okay";
+};
+
+&axp_gpio {
+ status = "okay";
+};
+
+&battery_power_supply {
+ status = "okay";
+};
+
+&usb_power_supply {
+ status = "okay";
+};
+
&reg_dcdc2 {
regulator-always-on;
regulator-min-microvolt = <1000000>;
@@ -133,7 +149,6 @@
regulator-max-microvolt = <3300000>;
regulator-name = "avcc-pll";
};
-*/
&reg_vcc3v0 {
regulator-always-on;
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index 376a99b7..0718d191 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -169,7 +169,7 @@ static const struct regulator_desc axp20x_regulators[] = {
AXP20X_DCDC2_V_OUT, 0x3f, AXP20X_PWR_OUT_CTRL, 0x10),
AXP_DESC(AXP20X, DCDC3, "dcdc3", "vin3", 700, 3500, 25,
AXP20X_DCDC3_V_OUT, 0x7f, AXP20X_PWR_OUT_CTRL, 0x02),
- AXP_DESC_FIXED(AXP20X, LDO1, "ldo1", "acin", 1300),
+ AXP_DESC_FIXED(AXP20X, LDO1, "ldo1", "acin", 3300),
AXP_DESC(AXP20X, LDO2, "ldo2", "ldo24in", 1800, 3300, 100,
AXP20X_LDO24_V_OUT, 0xf0, AXP20X_PWR_OUT_CTRL, 0x04),
AXP_DESC(AXP20X, LDO3, "ldo3", "ldo3in", 700, 3500, 25,

View File

@ -1,77 +0,0 @@
From 8096f82b8211e2d75f57048a30961e1d8616364e Mon Sep 17 00:00:00 2001
From: vincent <vbusoenseirb@gmail.com>
Date: Sat, 26 Oct 2019 10:44:34 +0200
Subject: [PATCH] fbtft set to 39Hz refresh rate
---
drivers/staging/fbtft/fb_st7789v.c | 16 +++++++++++++---
drivers/staging/fbtft/fbtft-core.c | 8 +++++++-
2 files changed, 20 insertions(+), 4 deletions(-)
mode change 100644 => 100755 drivers/staging/fbtft/fb_st7789v.c
mode change 100644 => 100755 drivers/staging/fbtft/fbtft-core.c
diff --git a/drivers/staging/fbtft/fb_st7789v.c b/drivers/staging/fbtft/fb_st7789v.c
old mode 100644
new mode 100755
index 69f52af..00756de
--- a/drivers/staging/fbtft/fb_st7789v.c
+++ b/drivers/staging/fbtft/fb_st7789v.c
@@ -150,12 +150,12 @@ static int init_display(struct fbtft_par *par)
*/
write_reg(par, PWCTRL1, 0xA4, 0xA1);
- /* Ystart at 80 , Yend at 240 */
- write_reg(par, 0x2B, 0x00, 0x50, 0x00, 0xF0);
-
/* Display Inversion of colors */
write_reg(par, 0x21);
+ /* 39Hz refresh rate */
+ write_reg(par, 0xC6,0x1F);
+
write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
return 0;
@@ -190,6 +190,16 @@ static int set_var(struct fbtft_par *par)
return -EINVAL;
}
write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, madctl_par);
+
+ // All offset operations are done after in fbtft_set_addr_win, not here
+ /* Ystart at 0 , Yend at 239 */
+ //write_reg(par, 0x2B, 0x00, 0x50, 0x00, 0xEF);
+ write_reg(par, 0x2B, 0x00, 0x00, 0x00, 0xEF);
+ //write_reg(par, 0x2B, 0x00, 0x50, 0x01, 0x3F);
+ /* Xstart at 80 , Xend at 319 */
+ write_reg(par, 0x2A, 0x00, 0x50, 0x01, 0x3F);
+ //write_reg(par, 0x2A, 0x00, 0x50, 0x00, 0xEF);
+
return 0;
}
diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
old mode 100644
new mode 100755
index 6d0363d..7fbf92e
--- a/drivers/staging/fbtft/fbtft-core.c
+++ b/drivers/staging/fbtft/fbtft-core.c
@@ -391,9 +391,15 @@ static void fbtft_update_display(struct fbtft_par *par, unsigned int start_line,
fbtft_par_dbg(DEBUG_UPDATE_DISPLAY, par, "%s(start_line=%u, end_line=%u)\n",
__func__, start_line, end_line);
- if (par->fbtftops.set_addr_win)
+ // Carefull removing this. this will work only if the full screen is updated all at once
+ if (par->fbtftops.set_addr_win){
par->fbtftops.set_addr_win(par, 0, start_line,
par->info->var.xres - 1, end_line);
+ }
+ /*if (par->fbtftops.set_addr_win){
+ par->fbtftops.set_addr_win(par, 80, start_line,
+ 320 - 1, end_line);
+ }*/
offset = start_line * par->info->fix.line_length;
len = (end_line - start_line + 1) * par->info->fix.line_length;
--
1.9.1

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +0,0 @@
diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s.dtsi
index 5379f2d7..f9765995 100644
--- a/arch/arm/boot/dts/sun8i-v3s.dtsi
+++ b/arch/arm/boot/dts/sun8i-v3s.dtsi
@@ -73,6 +73,17 @@
device_type = "cpu";
reg = <0>;
clocks = <&ccu CLK_CPU>;
+ clock-latency = <244144>; /* 8 32k periods */
+ clock-frequency = <1296000>;
+ operating-points = <
+ /* kHz uV */
+ 1296000 1200000
+ 1008000 1200000
+ 864000 1200000
+ 720000 1100000
+ 480000 1000000
+ >;
+
};
};

View File

@ -1,39 +0,0 @@
diff --git a/arch/arm/boot/dts/sun8i-v3s-funkey.dts b/arch/arm/boot/dts/sun8i-v3s-funkey.dts
index ad694808..3be3c7f1 100644
--- a/arch/arm/boot/dts/sun8i-v3s-funkey.dts
+++ b/arch/arm/boot/dts/sun8i-v3s-funkey.dts
@@ -74,6 +74,10 @@
status = "okay";
};
+&codec_analog {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s.dtsi
index 5379f2d7..02f6c844 100644
--- a/arch/arm/boot/dts/sun8i-v3s.dtsi
+++ b/arch/arm/boot/dts/sun8i-v3s.dtsi
@@ -433,6 +444,7 @@
codec_analog: codec-analog@01c23000 {
compatible = "allwinner,sun8i-v3s-codec-analog";
reg = <0x01c23000 0x4>;
+ status = "disabled";
};
uart0: serial@01c28000 {
diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
index 4a9ef673..655780ab 100644
--- a/sound/soc/sunxi/Makefile
+++ b/sound/soc/sunxi/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o
obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o
obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
-obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o
obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o

View File

@ -1,45 +0,0 @@
From fcef516f0bb110628d43c23320ef36389f689439 Mon Sep 17 00:00:00 2001
From: vincent <vbusoenseirb@gmail.com>
Date: Sun, 27 Oct 2019 16:39:04 +0100
Subject: [PATCH] axp209 PEK linked to KEY_Q, not KEY_POWER
---
drivers/input/misc/axp20x-pek.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c
index debeeae..5dac8e9 100644
--- a/drivers/input/misc/axp20x-pek.c
+++ b/drivers/input/misc/axp20x-pek.c
@@ -214,10 +214,14 @@ static irqreturn_t axp20x_pek_irq(int irq, void *pwr)
* The power-button is connected to ground so a falling edge (dbf)
* means it is pressed.
*/
- if (irq == axp20x_pek->irq_dbf)
- input_report_key(idev, KEY_POWER, true);
- else if (irq == axp20x_pek->irq_dbr)
- input_report_key(idev, KEY_POWER, false);
+ if (irq == axp20x_pek->irq_dbf){
+ //input_report_key(idev, KEY_POWER, true);
+ input_report_key(idev, KEY_Q, true);
+ }
+ else if (irq == axp20x_pek->irq_dbr){
+ //input_report_key(idev, KEY_POWER, false);
+ input_report_key(idev, KEY_Q, false);
+ }
input_sync(idev);
@@ -259,7 +263,8 @@ static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek,
idev->phys = "m1kbd/input2";
idev->dev.parent = &pdev->dev;
- input_set_capability(idev, EV_KEY, KEY_POWER);
+ //input_set_capability(idev, EV_KEY, KEY_POWER);
+ input_set_capability(idev, EV_KEY, KEY_Q);
input_set_drvdata(idev, axp20x_pek);
--
1.9.1

View File

@ -1,43 +0,0 @@
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 284bd1a7..97db9fa4 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -973,15 +973,19 @@ static void usb_gadget_state_work(struct work_struct *work)
struct usb_gadget *gadget = work_to_gadget(work);
struct usb_udc *udc = gadget->udc;
- if (udc)
+ if (udc) {
sysfs_notify(&udc->dev.kobj, NULL, "state");
+ kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
+ }
}
void usb_gadget_set_state(struct usb_gadget *gadget,
enum usb_device_state state)
{
- gadget->state = state;
- schedule_work(&gadget->work);
+ if (state != gadget->state) {
+ gadget->state = state;
+ schedule_work(&gadget->work);
+ }
}
EXPORT_SYMBOL_GPL(usb_gadget_set_state);
@@ -1565,6 +1569,15 @@ static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env)
}
}
+ if (udc->gadget) {
+ ret = add_uevent_var(env, "USB_UDC_STATE=%s",
+ usb_state_string(udc->gadget->state));
+ if (ret) {
+ dev_err(dev, "failed to add uevent USB_UDC_STATE\n");
+ return ret;
+ }
+ }
+
return 0;
}

View File

@ -1,173 +0,0 @@
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 8533f4e..88ad45e 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -88,8 +88,12 @@
#define SUN6I_TXDATA_REG 0x200
#define SUN6I_RXDATA_REG 0x300
+#define SUN6I_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST)
+
+#define SUN6I_SPI_MAX_SPEED_HZ 100000000
+#define SUN6I_SPI_MIN_SPEED_HZ 3000
+
struct sun6i_spi {
- struct spi_master *master;
void __iomem *base_addr;
struct clk *hclk;
struct clk *mclk;
@@ -189,6 +193,9 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
else
reg &= ~SUN6I_TFR_CTL_CS_LEVEL;
+ /* We want to control the chip select manually */
+ reg |= SUN6I_TFR_CTL_CS_MANUAL;
+
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
}
@@ -197,6 +204,39 @@ static size_t sun6i_spi_max_transfer_size(struct spi_device *spi)
return SUN6I_MAX_XFER_SIZE - 1;
}
+static int sun6i_spi_prepare_message(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct spi_device *spi = msg->spi;
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ u32 reg;
+
+ /*
+ * Setup the transfer control register: Chip Select,
+ * polarities, etc.
+ */
+ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+
+ if (spi->mode & SPI_CPOL)
+ reg |= SUN6I_TFR_CTL_CPOL;
+ else
+ reg &= ~SUN6I_TFR_CTL_CPOL;
+
+ if (spi->mode & SPI_CPHA)
+ reg |= SUN6I_TFR_CTL_CPHA;
+ else
+ reg &= ~SUN6I_TFR_CTL_CPHA;
+
+ if (spi->mode & SPI_LSB_FIRST)
+ reg |= SUN6I_TFR_CTL_FBS;
+ else
+ reg &= ~SUN6I_TFR_CTL_FBS;
+
+ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+
+ return 0;
+}
+
static int sun6i_spi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *tfr)
@@ -235,27 +275,8 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
(trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) |
(trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS));
- /*
- * Setup the transfer control register: Chip Select,
- * polarities, etc.
- */
- reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
-
- if (spi->mode & SPI_CPOL)
- reg |= SUN6I_TFR_CTL_CPOL;
- else
- reg &= ~SUN6I_TFR_CTL_CPOL;
-
- if (spi->mode & SPI_CPHA)
- reg |= SUN6I_TFR_CTL_CPHA;
- else
- reg &= ~SUN6I_TFR_CTL_CPHA;
-
- if (spi->mode & SPI_LSB_FIRST)
- reg |= SUN6I_TFR_CTL_FBS;
- else
- reg &= ~SUN6I_TFR_CTL_FBS;
+ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
/*
* If it's a TX only transfer, we don't want to fill the RX
* FIFO with bogus data
@@ -265,11 +286,9 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
else
reg |= SUN6I_TFR_CTL_DHB;
- /* We want to control the chip select manually */
- reg |= SUN6I_TFR_CTL_CS_MANUAL;
-
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+
/* Ensure that we have a parent clock fast enough */
mclk_rate = clk_get_rate(sspi->mclk);
if (mclk_rate < (2 * tfr->speed_hz)) {
@@ -442,12 +461,24 @@ static int sun6i_spi_probe(struct platform_device *pdev)
struct resource *res;
int ret = 0, irq;
- master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
+ master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
if (!master) {
dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
return -ENOMEM;
}
+ master->max_speed_hz = SUN6I_SPI_MAX_SPEED_HZ;
+ master->min_speed_hz = SUN6I_SPI_MIN_SPEED_HZ;
+ master->num_chipselect = 4;
+ master->mode_bits = SUN6I_SPI_MODE_BITS;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->set_cs = sun6i_spi_set_cs;
+ master->prepare_message = sun6i_spi_prepare_message;
+ master->transfer_one = sun6i_spi_transfer_one;
+ master->max_transfer_size = sun6i_spi_max_transfer_size;
+ master->dev.of_node = pdev->dev.of_node;
+ master->auto_runtime_pm = true;
+
platform_set_drvdata(pdev, master);
sspi = spi_master_get_devdata(master);
@@ -466,26 +497,14 @@ static int sun6i_spi_probe(struct platform_device *pdev)
}
ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler,
- 0, "sun6i-spi", sspi);
+ 0, dev_name(&pdev->dev), sspi);
if (ret) {
dev_err(&pdev->dev, "Cannot request IRQ\n");
goto err_free_master;
}
- sspi->master = master;
sspi->fifo_depth = (unsigned long)of_device_get_match_data(&pdev->dev);
- master->max_speed_hz = 100 * 1000 * 1000;
- master->min_speed_hz = 3 * 1000;
- master->set_cs = sun6i_spi_set_cs;
- master->transfer_one = sun6i_spi_transfer_one;
- master->num_chipselect = 4;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->dev.of_node = pdev->dev.of_node;
- master->auto_runtime_pm = true;
- master->max_transfer_size = sun6i_spi_max_transfer_size;
-
sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(sspi->hclk)) {
dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
@@ -525,7 +544,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
ret = devm_spi_register_master(&pdev->dev, master);
if (ret) {
- dev_err(&pdev->dev, "cannot register SPI master\n");
+ dev_err(&pdev->dev, "Couldn't register SPI master\n");
goto err_pm_disable;
}

View File

@ -1,17 +0,0 @@
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 88ad45e..78acc1f 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -193,6 +193,12 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
else
reg &= ~SUN6I_TFR_CTL_CS_LEVEL;
+ /* Handle chip select "reverse" polarity */
+ if (spi->mode & SPI_CS_HIGH)
+ reg &= ~SUN6I_TFR_CTL_SPOL;
+ else
+ reg |= SUN6I_TFR_CTL_SPOL;
+
/* We want to control the chip select manually */
reg |= SUN6I_TFR_CTL_CS_MANUAL;

View File

@ -1,111 +0,0 @@
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 78acc1f..4db1f20 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -207,7 +207,10 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
static size_t sun6i_spi_max_transfer_size(struct spi_device *spi)
{
- return SUN6I_MAX_XFER_SIZE - 1;
+ struct spi_master *master = spi->master;
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+
+ return sspi->fifo_depth;
}
static int sun6i_spi_prepare_message(struct spi_master *master,
@@ -250,13 +253,18 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
struct sun6i_spi *sspi = spi_master_get_devdata(master);
unsigned int mclk_rate, div, timeout;
unsigned int start, end, tx_time;
- unsigned int trig_level;
unsigned int tx_len = 0;
int ret = 0;
u32 reg;
- if (tfr->len > SUN6I_MAX_XFER_SIZE)
- return -EINVAL;
+ /* A zero length transfer never finishes if programmed
+ in the hardware */
+ if (!tfr->len)
+ return 0;
+
+ /* Don't support transfer larger than the FIFO */
+ if (tfr->len > sspi->fifo_depth)
+ return -EMSGSIZE;
reinit_completion(&sspi->done);
sspi->tx_buf = tfr->tx_buf;
@@ -270,17 +278,6 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
- /*
- * Setup FIFO interrupt trigger level
- * Here we choose 3/4 of the full fifo depth, as it's the hardcoded
- * value used in old generation of Allwinner SPI controller.
- * (See spi-sun4i.c)
- */
- trig_level = sspi->fifo_depth / 4 * 3;
- sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
- (trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) |
- (trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS));
-
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
/*
@@ -342,12 +339,8 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
/* Fill the TX FIFO */
sun6i_spi_fill_fifo(sspi, sspi->fifo_depth);
- /* Enable the interrupts */
- sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
- sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC |
- SUN6I_INT_CTL_RF_RDY);
- if (tx_len > sspi->fifo_depth)
- sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ);
+ /* Enable transfer complete interrupt */
+ sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC);
/* Start the transfer */
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
@@ -376,7 +369,9 @@ out:
static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
{
struct sun6i_spi *sspi = dev_id;
- u32 status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
+ u32 status;
+
+ status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
/* Transfer complete */
if (status & SUN6I_INT_CTL_TC) {
@@ -386,28 +381,6 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
- /* Receive FIFO 3/4 full */
- if (status & SUN6I_INT_CTL_RF_RDY) {
- sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH);
- /* Only clear the interrupt _after_ draining the FIFO */
- sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_RF_RDY);
- return IRQ_HANDLED;
- }
-
- /* Transmit FIFO 3/4 empty */
- if (status & SUN6I_INT_CTL_TF_ERQ) {
- sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH);
-
- if (!sspi->len)
- /* nothing left to transmit */
- sun6i_spi_disable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ);
-
- /* Only clear the interrupt _after_ re-seeding the FIFO */
- sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TF_ERQ);
-
- return IRQ_HANDLED;
- }
-
return IRQ_NONE;
}

View File

@ -1,113 +0,0 @@
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 4db1f20..210cef9 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -99,8 +99,6 @@ struct sun6i_spi {
struct clk *mclk;
struct reset_control *rstc;
- struct completion done;
-
const u8 *tx_buf;
u8 *rx_buf;
int len;
@@ -246,6 +244,30 @@ static int sun6i_spi_prepare_message(struct spi_master *master,
return 0;
}
+static int sun6i_spi_wait_for_transfer(struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+ struct spi_master *master = spi->master;
+ unsigned int start, end, tx_time;
+ unsigned int timeout;
+
+ /* smart wait for completion */
+ tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
+ start = jiffies;
+ timeout = wait_for_completion_timeout(&master->xfer_completion,
+ msecs_to_jiffies(tx_time));
+ end = jiffies;
+ if (!timeout) {
+ dev_warn(&master->dev,
+ "%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
+ dev_name(&spi->dev), tfr->len, tfr->speed_hz,
+ jiffies_to_msecs(end - start), tx_time);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
static int sun6i_spi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *tfr)
@@ -266,7 +288,6 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
if (tfr->len > sspi->fifo_depth)
return -EMSGSIZE;
- reinit_completion(&sspi->done);
sspi->tx_buf = tfr->tx_buf;
sspi->rx_buf = tfr->rx_buf;
sspi->len = tfr->len;
@@ -346,21 +367,9 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
- tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
- start = jiffies;
- timeout = wait_for_completion_timeout(&sspi->done,
- msecs_to_jiffies(tx_time));
- end = jiffies;
- if (!timeout) {
- dev_warn(&master->dev,
- "%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
- dev_name(&spi->dev), tfr->len, tfr->speed_hz,
- jiffies_to_msecs(end - start), tx_time);
- ret = -ETIMEDOUT;
- goto out;
- }
+ /* Wait for completion */
+ ret = sun6i_spi_wait_for_transfer(spi, tfr);
-out:
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
return ret;
@@ -368,7 +377,8 @@ out:
static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
{
- struct sun6i_spi *sspi = dev_id;
+ struct spi_master *master = dev_id;
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
u32 status;
status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
@@ -377,7 +387,7 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
if (status & SUN6I_INT_CTL_TC) {
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC);
sun6i_spi_drain_fifo(sspi, sspi->fifo_depth);
- complete(&sspi->done);
+ spi_finalize_current_transfer(master);
return IRQ_HANDLED;
}
@@ -476,7 +486,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
}
ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler,
- 0, dev_name(&pdev->dev), sspi);
+ 0, dev_name(&pdev->dev), master);
if (ret) {
dev_err(&pdev->dev, "Cannot request IRQ\n");
goto err_free_master;
@@ -498,8 +508,6 @@ static int sun6i_spi_probe(struct platform_device *pdev)
goto err_free_master;
}
- init_completion(&sspi->done);
-
sspi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(sspi->rstc)) {
dev_err(&pdev->dev, "Couldn't get reset controller\n");

View File

@ -1,82 +0,0 @@
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 210cef9..18f9344 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -115,29 +115,29 @@ static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value)
writel(value, sspi->base_addr + reg);
}
-static inline u32 sun6i_spi_get_tx_fifo_count(struct sun6i_spi *sspi)
+static inline void sun6i_spi_set(struct sun6i_spi *sspi, u32 addr, u32 val)
{
- u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
-
- reg >>= SUN6I_FIFO_STA_TF_CNT_BITS;
+ u32 reg = sun6i_spi_read(sspi, addr);
- return reg & SUN6I_FIFO_STA_TF_CNT_MASK;
+ reg |= val;
+ sun6i_spi_write(sspi, addr, reg);
}
-static inline void sun6i_spi_enable_interrupt(struct sun6i_spi *sspi, u32 mask)
+static inline void sun6i_spi_unset(struct sun6i_spi *sspi, u32 addr, u32 val)
{
- u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG);
+ u32 reg = sun6i_spi_read(sspi, addr);
- reg |= mask;
- sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
+ reg &= ~val;
+ sun6i_spi_write(sspi, addr, reg);
}
-static inline void sun6i_spi_disable_interrupt(struct sun6i_spi *sspi, u32 mask)
+static inline u32 sun6i_spi_get_tx_fifo_count(struct sun6i_spi *sspi)
{
- u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG);
+ u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
- reg &= ~mask;
- sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
+ reg >>= SUN6I_FIFO_STA_TF_CNT_BITS;
+
+ return reg & SUN6I_FIFO_STA_TF_CNT_MASK;
}
static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
@@ -299,18 +299,14 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
-
- reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
/*
* If it's a TX only transfer, we don't want to fill the RX
* FIFO with bogus data
*/
if (sspi->rx_buf)
- reg &= ~SUN6I_TFR_CTL_DHB;
+ sun6i_spi_unset(sspi, SUN6I_TFR_CTL_REG, SUN6I_TFR_CTL_DHB);
else
- reg |= SUN6I_TFR_CTL_DHB;
-
- sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+ sun6i_spi_set(sspi, SUN6I_TFR_CTL_REG, SUN6I_TFR_CTL_DHB);
/* Ensure that we have a parent clock fast enough */
@@ -361,11 +357,10 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
sun6i_spi_fill_fifo(sspi, sspi->fifo_depth);
/* Enable transfer complete interrupt */
- sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC);
+ sun6i_spi_set(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
/* Start the transfer */
- reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
- sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
+ sun6i_spi_set(sspi, SUN6I_TFR_CTL_REG, SUN6I_TFR_CTL_XCH);
/* Wait for completion */
ret = sun6i_spi_wait_for_transfer(spi, tfr);

View File

@ -1,390 +0,0 @@
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 18f9344..5665c84 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -14,6 +14,8 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -55,11 +57,14 @@
#define SUN6I_FIFO_CTL_REG 0x18
#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_MASK 0xff
-#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS 0
+#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_POS 0
+#define SUN6I_FIFO_CTL_RF_DRQ_EN BIT(8)
#define SUN6I_FIFO_CTL_RF_RST BIT(15)
#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_MASK 0xff
-#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS 16
+#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_POS 16
+#define SUN6I_FIFO_CTL_TF_DRQ_EN BIT(24)
#define SUN6I_FIFO_CTL_TF_RST BIT(31)
+#define SUN6I_FIFO_CTL_DMA_DEDICATE BIT(9)|BIT(25)
#define SUN6I_FIFO_STA_REG 0x1c
#define SUN6I_FIFO_STA_RF_CNT_MASK 0x7f
@@ -177,6 +182,15 @@ static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len)
}
}
+static bool sun6i_spi_can_dma(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+
+ return tfr->len > sspi->fifo_depth;
+}
+
static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
{
struct sun6i_spi *sspi = spi_master_get_devdata(spi->master);
@@ -208,6 +222,9 @@ static size_t sun6i_spi_max_transfer_size(struct spi_device *spi)
struct spi_master *master = spi->master;
struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ if (master->can_dma)
+ return SUN6I_MAX_XFER_SIZE;
+
return sspi->fifo_depth;
}
@@ -268,15 +285,174 @@ static int sun6i_spi_wait_for_transfer(struct spi_device *spi,
return 0;
}
+static void sun6i_spi_dma_callback(void *param)
+{
+ struct spi_master *master = param;
+
+ dev_dbg(&master->dev, "DMA transfer complete\n");
+ spi_finalize_current_transfer(master);
+}
+
+static int sun6i_spi_dmap_prep_tx(struct spi_master *master,
+ struct spi_transfer *tfr,
+ dma_cookie_t *cookie)
+{
+ struct dma_async_tx_descriptor *chan_desc = NULL;
+
+ chan_desc = dmaengine_prep_slave_sg(master->dma_tx,
+ tfr->tx_sg.sgl, tfr->tx_sg.nents,
+ DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!chan_desc) {
+ dev_err(&master->dev,
+ "Couldn't prepare TX DMA slave\n");
+ return -EIO;
+ }
+
+ chan_desc->callback = sun6i_spi_dma_callback;
+ chan_desc->callback_param = master;
+
+ *cookie = dmaengine_submit(chan_desc);
+ dma_async_issue_pending(master->dma_tx);
+
+ return 0;
+}
+
+static int sun6i_spi_dmap_prep_rx(struct spi_master *master,
+ struct spi_transfer *tfr,
+ dma_cookie_t *cookie)
+{
+ struct dma_async_tx_descriptor *chan_desc = NULL;
+
+ chan_desc = dmaengine_prep_slave_sg(master->dma_rx,
+ tfr->rx_sg.sgl, tfr->rx_sg.nents,
+ DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!chan_desc) {
+ dev_err(&master->dev,
+ "Couldn't prepare RX DMA slave\n");
+ return -EIO;
+ }
+
+ chan_desc->callback = sun6i_spi_dma_callback;
+ chan_desc->callback_param = master;
+
+ *cookie = dmaengine_submit(chan_desc);
+ dma_async_issue_pending(master->dma_rx);
+
+ return 0;
+}
+
+static int sun6i_spi_transfer_one_dma(struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+ struct spi_master *master = spi->master;
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ dma_cookie_t tx_cookie = 0,rx_cookie = 0;
+ enum dma_status status;
+ int ret;
+ u32 reg, trig_level = 0;
+
+ dev_dbg(&master->dev, "Using DMA mode for transfer\n");
+
+ reg = sun6i_spi_read(sspi, SUN6I_FIFO_CTL_REG);
+
+ if (sspi->tx_buf) {
+ ret = sun6i_spi_dmap_prep_tx(master, tfr, &tx_cookie);
+ if (ret)
+ goto out;
+
+ reg |= SUN6I_FIFO_CTL_TF_DRQ_EN;
+
+ trig_level = sspi->fifo_depth;
+ reg &= ~SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_MASK;
+ reg |= (trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_POS);
+ }
+
+ if (sspi->rx_buf) {
+ ret = sun6i_spi_dmap_prep_rx(master, tfr, &rx_cookie);
+ if (ret)
+ goto out;
+
+ reg |= SUN6I_FIFO_CTL_RF_DRQ_EN;
+
+ trig_level = 1;
+ reg &= ~SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_MASK;
+ reg |= (trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_POS);
+ }
+
+ /* Enable Dedicated DMA requests */
+ sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
+ reg | SUN6I_FIFO_CTL_DMA_DEDICATE);
+
+ /* Start transfer */
+ sun6i_spi_set(sspi, SUN6I_TFR_CTL_REG, SUN6I_TFR_CTL_XCH);
+
+ ret = sun6i_spi_wait_for_transfer(spi, tfr);
+ if (ret)
+ goto out;
+
+ if (sspi->tx_buf && (status = dma_async_is_tx_complete(master->dma_tx,
+ tx_cookie, NULL, NULL))) {
+ dev_warn(&master->dev,
+ "DMA returned completion status of: %s\n",
+ status == DMA_ERROR ? "error" : "in progress");
+ }
+ if (sspi->rx_buf && (status = dma_async_is_tx_complete(master->dma_rx,
+ rx_cookie, NULL, NULL))) {
+ dev_warn(&master->dev,
+ "DMA returned completion status of: %s\n",
+ status == DMA_ERROR ? "error" : "in progress");
+ }
+
+out:
+ if (ret) {
+ dev_dbg(&master->dev, "DMA channel teardown\n");
+ if (sspi->tx_buf)
+ dmaengine_terminate_sync(master->dma_tx);
+ if (sspi->rx_buf)
+ dmaengine_terminate_sync(master->dma_rx);
+ }
+
+ sun6i_spi_drain_fifo(sspi, sspi->fifo_depth);
+
+ sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
+
+ return ret;
+}
+
+static int sun6i_spi_transfer_one_pio(struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+ struct spi_master *master = spi->master;
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ int ret;
+
+ /* Disable DMA requests */
+ sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG, 0);
+
+ sun6i_spi_fill_fifo(sspi, sspi->fifo_depth);
+
+ /* Enable transfer complete IRQ */
+ sun6i_spi_set(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
+
+ /* Start transfer */
+ sun6i_spi_set(sspi, SUN6I_TFR_CTL_REG, SUN6I_TFR_CTL_XCH);
+
+ ret = sun6i_spi_wait_for_transfer(spi, tfr);
+
+ sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
+
+ return ret;
+}
+
static int sun6i_spi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *tfr)
{
struct sun6i_spi *sspi = spi_master_get_devdata(master);
- unsigned int mclk_rate, div, timeout;
- unsigned int start, end, tx_time;
+ unsigned int mclk_rate, div;
unsigned int tx_len = 0;
- int ret = 0;
u32 reg;
/* A zero length transfer never finishes if programmed
@@ -284,10 +460,15 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
if (!tfr->len)
return 0;
- /* Don't support transfer larger than the FIFO */
- if (tfr->len > sspi->fifo_depth)
+ if (tfr->len > SUN6I_MAX_XFER_SIZE)
return -EMSGSIZE;
+ if (!master->can_dma) {
+ /* Don't support transfer larger than the FIFO */
+ if (tfr->len > sspi->fifo_depth)
+ return -EMSGSIZE;
+ }
+
sspi->tx_buf = tfr->tx_buf;
sspi->rx_buf = tfr->rx_buf;
sspi->len = tfr->len;
@@ -353,21 +534,10 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG,
SUN6I_BURST_CTL_CNT_STC(tx_len));
- /* Fill the TX FIFO */
- sun6i_spi_fill_fifo(sspi, sspi->fifo_depth);
-
- /* Enable transfer complete interrupt */
- sun6i_spi_set(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
-
- /* Start the transfer */
- sun6i_spi_set(sspi, SUN6I_TFR_CTL_REG, SUN6I_TFR_CTL_XCH);
-
- /* Wait for completion */
- ret = sun6i_spi_wait_for_transfer(spi, tfr);
-
- sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
+ if (sun6i_spi_can_dma(master, spi, tfr))
+ return sun6i_spi_transfer_one_dma(spi, tfr);
- return ret;
+ return sun6i_spi_transfer_one_pio(spi, tfr);
}
static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
@@ -389,6 +559,76 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
return IRQ_NONE;
}
+static int sun6i_spi_dma_setup(struct platform_device *pdev,
+ struct resource *res)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct dma_slave_config dma_sconf;
+ int ret;
+
+ master->dma_tx = dma_request_slave_channel_reason(&pdev->dev, "tx");
+ if (IS_ERR(master->dma_tx)) {
+ dev_err(&pdev->dev, "Unable to acquire DMA TX channel\n");
+ ret = PTR_ERR(master->dma_tx);
+ goto out;
+ }
+
+ dma_sconf.direction = DMA_MEM_TO_DEV;
+ dma_sconf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_sconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_sconf.dst_addr = res->start + SUN6I_TXDATA_REG;
+ dma_sconf.src_maxburst = 1;
+ dma_sconf.dst_maxburst = 1;
+
+ ret = dmaengine_slave_config(master->dma_tx, &dma_sconf);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to configure DMA TX slave\n");
+ goto err_rel_tx;
+ }
+
+ master->dma_rx = dma_request_slave_channel_reason(&pdev->dev, "rx");
+ if (IS_ERR(master->dma_rx)) {
+ dev_err(&pdev->dev, "Unable to acquire DMA RX channel\n");
+ ret = PTR_ERR(master->dma_rx);
+ goto err_rel_tx;
+ }
+
+ dma_sconf.direction = DMA_DEV_TO_MEM;
+ dma_sconf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_sconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_sconf.src_addr = res->start + SUN6I_RXDATA_REG;
+ dma_sconf.src_maxburst = 1;
+ dma_sconf.dst_maxburst = 1;
+
+ ret = dmaengine_slave_config(master->dma_rx, &dma_sconf);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to configure DMA RX slave\n");
+ goto err_rel_rx;
+ }
+
+ /* don't set can_dma unless both channels are valid*/
+ master->can_dma = sun6i_spi_can_dma;
+
+ return 0;
+
+err_rel_rx:
+ dma_release_channel(master->dma_rx);
+err_rel_tx:
+ dma_release_channel(master->dma_tx);
+out:
+ master->dma_tx = NULL;
+ master->dma_rx = NULL;
+ return ret;
+}
+
+static void sun6i_spi_dma_release(struct spi_master *master)
+{
+ if (master->can_dma) {
+ dma_release_channel(master->dma_rx);
+ dma_release_channel(master->dma_tx);
+ }
+}
+
static int sun6i_spi_runtime_resume(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
@@ -510,6 +750,15 @@ static int sun6i_spi_probe(struct platform_device *pdev)
goto err_free_master;
}
+ ret = sun6i_spi_dma_setup(pdev, res);
+ if (ret) {
+ if (ret == -EPROBE_DEFER) {
+ /* wait for the dma driver to load */
+ goto err_free_master;
+ }
+ dev_warn(&pdev->dev, "DMA transfer not supported\n");
+ }
+
/*
* This wake-up/shutdown pattern is to be able to have the
* device woken up, even if runtime_pm is disabled
@@ -536,14 +785,19 @@ err_pm_disable:
pm_runtime_disable(&pdev->dev);
sun6i_spi_runtime_suspend(&pdev->dev);
err_free_master:
+ sun6i_spi_dma_release(master);
spi_master_put(master);
return ret;
}
static int sun6i_spi_remove(struct platform_device *pdev)
{
+ struct spi_master *master = platform_get_drvdata(pdev);
+
pm_runtime_disable(&pdev->dev);
+ sun6i_spi_dma_release(master);
+
return 0;
}

View File

@ -1,55 +0,0 @@
From 3b489a63e4e05489411a032cb60d8939a81f14b7 Mon Sep 17 00:00:00 2001
From: vincent <vbusoenseirb@gmail.com>
Date: Tue, 5 Nov 2019 18:53:47 +0100
Subject: [PATCH] added SPI DMA declaration in device tree and bigger tx_buf
size in fbtft (1 byte more to support start byte)
---
arch/arm/boot/dts/sun8i-v3s-funkey.dts | 3 ++-
arch/arm/boot/dts/sun8i-v3s.dtsi | 2 ++
drivers/staging/fbtft/fbtft-core.c | 2 +-
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/sun8i-v3s-funkey.dts b/arch/arm/boot/dts/sun8i-v3s-funkey.dts
index 78f4d6a..19062fc 100644
--- a/arch/arm/boot/dts/sun8i-v3s-funkey.dts
+++ b/arch/arm/boot/dts/sun8i-v3s-funkey.dts
@@ -176,7 +176,8 @@
compatible = "sitronix,st7789v";
reg = <0>;
spi-max-frequency = <50000000>;
- txbuflen = <115200>;
+ txbuflen = <115202>;
+// txbuflen = <0>;
rotate = <0>;
fps = <50>;
buswidth = <8>;
diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s.dtsi
index 02f6c84..f5ca5a5 100644
--- a/arch/arm/boot/dts/sun8i-v3s.dtsi
+++ b/arch/arm/boot/dts/sun8i-v3s.dtsi
@@ -539,6 +539,8 @@
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
clock-names = "ahb", "mod";
+ dmas = <&dma 23>, <&dma 23>;
+ dma-names = "rx", "tx";
pinctrl-names = "default";
pinctrl-0 = <&spi0_pins>;
resets = <&ccu RST_BUS_SPI0>;
diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
index 7fbf92e..7dce967 100755
--- a/drivers/staging/fbtft/fbtft-core.c
+++ b/drivers/staging/fbtft/fbtft-core.c
@@ -840,7 +840,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
/* Transmit buffer */
if (txbuflen == -1)
txbuflen = vmem_size + 2; /* add in case startbyte is used */
- if (txbuflen >= vmem_size + 2)
+ if (txbuflen > vmem_size + 2)
txbuflen = 0;
#ifdef __LITTLE_ENDIAN
--
1.9.1

View File

@ -1,27 +0,0 @@
From ff9cbaaeb217a6cf2e2fffde614abfdfb3f6cf5d Mon Sep 17 00:00:00 2001
From: vincent <vbusoenseirb@gmail.com>
Date: Tue, 19 Nov 2019 14:02:56 +0100
Subject: [PATCH] changed st7789v gamma
---
drivers/staging/fbtft/fb_st7789v.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/fbtft/fb_st7789v.c b/drivers/staging/fbtft/fb_st7789v.c
index 00756de..212836f 100755
--- a/drivers/staging/fbtft/fb_st7789v.c
+++ b/drivers/staging/fbtft/fb_st7789v.c
@@ -26,8 +26,8 @@
#define DRVNAME "fb_st7789v"
#define DEFAULT_GAMMA \
- "70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25\n" \
- "70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25"
+ "f0 19 1e 0A 09 15 3D 44 51 19 14 13 2c 31\n" \
+ "f0 18 1E 0A 09 25 3F 43 52 19 14 13 2c 31"
/**
* enum st7789v_command - ST7789V display controller commands
--
1.9.1

View File

@ -1,851 +0,0 @@
From 71fc9be7b624c13355d37fa85162ba4f24e5d248 Mon Sep 17 00:00:00 2001
From: vincent <vbusoenseirb@gmail.com>
Date: Thu, 26 Dec 2019 17:29:03 +0100
Subject: [PATCH] added fbtft boot logo, soft rotate and fixed soft tearing
issue
---
arch/arm/boot/dts/sun8i-v3s-funkey.dts | 3 +-
drivers/staging/fbtft/fb_st7789v.c | 5 +-
drivers/staging/fbtft/fb_text.c | 59 ++++++++
drivers/staging/fbtft/fb_text.h | 2 +-
drivers/staging/fbtft/fbtft-bus.c | 256 ++++++++++++++++++++++++++++-----
drivers/staging/fbtft/fbtft-core.c | 148 +++++++++++++++----
drivers/staging/fbtft/fbtft-io.c | 5 +-
drivers/staging/fbtft/fbtft-sysfs.c | 31 ++++
drivers/staging/fbtft/fbtft.h | 16 ++-
9 files changed, 452 insertions(+), 73 deletions(-)
diff --git a/arch/arm/boot/dts/sun8i-v3s-funkey.dts b/arch/arm/boot/dts/sun8i-v3s-funkey.dts
index 88f1c0f..d25521c 100644
--- a/arch/arm/boot/dts/sun8i-v3s-funkey.dts
+++ b/arch/arm/boot/dts/sun8i-v3s-funkey.dts
@@ -179,8 +179,9 @@
txbuflen = <115202>;
// txbuflen = <0>;
spi_async_mode = "true";
+ //interlacing = "true";
rotate = <0>;
- rotate_soft = <0>;
+ rotate_soft = <270>;
fps = <100>;
buswidth = <8>;
reset-gpios = <&pio 4 1 GPIO_ACTIVE_LOW>; //PE1
diff --git a/drivers/staging/fbtft/fb_st7789v.c b/drivers/staging/fbtft/fb_st7789v.c
index ba21ab5..e2c9078 100755
--- a/drivers/staging/fbtft/fb_st7789v.c
+++ b/drivers/staging/fbtft/fb_st7789v.c
@@ -157,12 +157,15 @@ static int init_display(struct fbtft_par *par)
//write_reg(par, 0xC6,0x1F); //39Hz
//write_reg(par, 0xC6,0x1A); //44Hz
//write_reg(par, 0xC6,0x17); //48Hz
+ //write_reg(par, 0xC6,0x16); //49Hz
//write_reg(par, 0xC6,0x15); //50Hz
+ //write_reg(par, 0xC6,0x14); //52Hz
//write_reg(par, 0xC6,0x12); //55Hz
//write_reg(par, 0xC6,0x10); //58Hz
//write_reg(par, 0xC6,0x0F); //60Hz
- write_reg(par, 0xC6,0x09); //60Hz
+ //write_reg(par, 0xC6,0x09); //60Hz
//write_reg(par, 0xC6,0x03); //99Hz
+ write_reg(par, 0xC6,0x02); //105Hz
write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
diff --git a/drivers/staging/fbtft/fb_text.c b/drivers/staging/fbtft/fb_text.c
index 9f873b5..650535d 100644
--- a/drivers/staging/fbtft/fb_text.c
+++ b/drivers/staging/fbtft/fb_text.c
@@ -4,6 +4,38 @@
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
+#define LOW_BATTERY_ICON_TOP_LEFT_X 10
+#define LOW_BATTERY_ICON_TOP_LEFT_Y 10
+#define LOW_BATTERY_ICON_WIDTH 35
+#define LOW_BATTERY_ICON_HEIGHT 20
+//#define LOW_BATTERY_FORE_COLOR 65535
+#define LOW_BATTERY_FORE_COLOR 0xF800
+#define LOW_BATTERY_BACK_COLOR 0
+
+
+// Battery icon from: https://github.com/martinohanlon/grrl-bat-monitor
+static u16 lowBatteryIcon [LOW_BATTERY_ICON_HEIGHT][LOW_BATTERY_ICON_WIDTH] = {
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
+ {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
+ {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
+ {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
+ {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
+ {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
+ {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0},
+ {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0},
+ {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0},
+ {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0},
+ {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
+ {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
+ {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
+ {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
+ {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
+ {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+
static u8 monaco_font[] = {
@@ -1548,3 +1580,30 @@ void DrawText(u16 *framebuffer, int framebufferWidth, int framebufferStrideBytes
x += 6;
}
}
+
+void draw_low_battery(u16 *framebuffer, int framebufferWidth, int framebufferHeight)
+{
+ int x_offset = LOW_BATTERY_ICON_TOP_LEFT_X;
+ int y_offset = LOW_BATTERY_ICON_TOP_LEFT_Y;
+ int x, y;
+
+ /* Sanity check - width */
+ if(x_offset >= framebufferWidth ){
+ x_offset = framebufferWidth-1-LOW_BATTERY_ICON_WIDTH;
+ }
+
+ /* Sanity check - height */
+ if(y_offset >= framebufferHeight ){
+ y_offset = framebufferHeight-1-LOW_BATTERY_ICON_HEIGHT;
+ }
+
+ /* Printing low battery icon */
+ for(y = 0; y < MIN(LOW_BATTERY_ICON_HEIGHT, framebufferHeight-y_offset); ++y){
+ for(x = 0; x < MIN(LOW_BATTERY_ICON_WIDTH, framebufferWidth-x_offset); ++x){
+ if(lowBatteryIcon[y][x]){
+ framebuffer[(y+y_offset)*framebufferWidth + (x+x_offset)] = LOW_BATTERY_FORE_COLOR;
+ }
+ //lowBatteryIcon[y][x] = lowBatteryIcon[y][x] ? LOW_BATTERY_FORE_COLOR : LOW_BATTERY_BACK_COLOR;
+ }
+ }
+}
\ No newline at end of file
diff --git a/drivers/staging/fbtft/fb_text.h b/drivers/staging/fbtft/fb_text.h
index 1352bdb..e03df39 100644
--- a/drivers/staging/fbtft/fb_text.h
+++ b/drivers/staging/fbtft/fb_text.h
@@ -10,7 +10,7 @@
#define RGB565(r, g, b) (((r&0x1f) << 11) | ((g&0x3f) << 5) | (b&0x1f))
void DrawText(u16 *framebuffer, int framebufferWidth, int framebufferStrideBytes, int framebufferHeight, const char *text, int x, int y, u16 color, u16 bgColor);
-
+void draw_low_battery(u16 *framebuffer, int framebufferWidth, int framebufferHeight);
/*extern unsigned char fontdata8x8[64*16];
extern unsigned char fontdata6x8[256-32][8];*/
diff --git a/drivers/staging/fbtft/fbtft-bus.c b/drivers/staging/fbtft/fbtft-bus.c
index 23488ea..ce865ed 100644
--- a/drivers/staging/fbtft/fbtft-bus.c
+++ b/drivers/staging/fbtft/fbtft-bus.c
@@ -7,6 +7,8 @@
#include <video/mipi_display.h>
#include "fbtft.h"
#include "fb_text.h"
+#include <linux/rmap.h>
+#include <linux/pagemap.h>
/*****************************************************************************
*
@@ -110,38 +112,203 @@ void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...)
-static void spi_complete_cmd_init_data_write(void *arg)
-{
- struct fbtft_par *par = (struct fbtft_par *) arg;
+
+
+static int prev_write_line_start = -1;
+static int prev_write_line_end = -1;
+static int write_line_start = -1;
+static int write_line_end = -1;
+static bool lock = false;
+
+
+
+int fbtft_start_new_screen_transfer_async(struct fbtft_par *par){
//printk("%s\n", __func__);
+ if(lock){
+ return -1;
+ }
+ lock = true;
+
+ /*if(par->write_line_start == -1 || par->write_line_end == -1){
+ lock = false;
+ return;
+ }*/
+
+ /* Debug fps */
+#define FPS_DEBUG 1
+#if FPS_DEBUG
+ long fps;
+ ktime_t ts_now = ktime_get();
+
+ /* First measurement */
+ if (!ktime_to_ns(par->update_time))
+ par->update_time = ts_now;
+
+ fps = ktime_us_delta(ts_now, par->update_time);
+ par->update_time = ts_now;
+ fps = fps ? 1000000 / fps : 0;
+
+ if(fps){
+ par->avg_fps += fps;
+ par->nb_fps_values++;
+
+ if(par->nb_fps_values == 200){
+ fbtft_par_dbg(DEBUG_TIME_EACH_UPDATE, par,
+ "Display update: fps=%ld\n", par->avg_fps/par->nb_fps_values);
+ par->avg_fps = 0;
+ par->nb_fps_values = 0;
+ }
+ }
+
+#endif //FPS_DEBUG
+
+ /* Post process screen for doufle buf cpy, notifs, rotation soft... */
+ fbtft_post_process_screen(par);
+
+ /* new line to write */
+ write_line_start = par->write_line_start;
+ write_line_end = par->write_line_end;
+ par->write_line_start = -1;
+ par->write_line_end = -1;
+
+ /* Set window for interlacing */
+ if(par->interlacing){
+ par->length_data_transfer = par->info->var.yres * 2;
+ write_line_start = par->odd_line?1:0;
+ write_line_end = write_line_start;
+ fbtft_write_cmd_window_line(par);
+
+ } /* Start sending full screen */
+ else{
+ /*par->length_data_transfer = (write_line_end - write_line_start + 1) * par->info->fix.line_length;
+ if(write_line_start != prev_write_line_start || write_line_end != prev_write_line_end){
+ prev_write_line_start = write_line_start;
+ prev_write_line_end = write_line_end;
+ fbtft_write_cmd_window_line(par);
+ }
+ else{
+ fbtft_write_init_cmd_data_transfers(par);
+ }*/
+
+
+ par->length_data_transfer = par->info->var.yres * par->info->fix.line_length;
+ write_line_start = 0;
+ write_line_end = par->info->var.yres-1;
+ fbtft_write_init_cmd_data_transfers(par);
+ }
+
- /* Start new data write (full display) */
- int len = par->info->var.yres * par->info->fix.line_length;
- fbtft_write_vmem16_bus8_async(par, 0, len);
-
+ return 0;
}
+EXPORT_SYMBOL(fbtft_start_new_screen_transfer_async);
-static void spi_complete_data_write(void *arg)
+
+
+
+
+
+
+
+static u8 cmd_window_line = MIPI_DCS_SET_PAGE_ADDRESS;
+static u8 buf_ylim[4];
+
+
+static void spi_complete_cmd_window_line(void *arg)
{
struct fbtft_par *par = (struct fbtft_par *) arg;
//printk("%s\n", __func__);
- /* sleep */
- //msleep(1);
+ /* Start data write for line info */
+ fbtft_write_data_window_line(par);
+}
+
+int fbtft_write_cmd_window_line(struct fbtft_par *par){
+
+ int ret = 0;
+
+ //printk("%s\n", __func__);
+
+ /* Resetting to 0 for incoming cmd init data write */
+ if (gpio_is_valid(par->gpio.dc))
+ gpio_set_value(par->gpio.dc, 0);
/* Start sending cmd init data */
+ ret = par->fbtftops.write_async(par, &cmd_window_line, 1, spi_complete_cmd_window_line);
+ if (ret < 0)
+ dev_err(par->info->device,
+ "write() failed and returned %d\n", ret);
+
+ return ret;
+
+}
+EXPORT_SYMBOL(fbtft_write_cmd_window_line);
+
+
+
+
+
+
+
+
+
+static void spi_complete_data_window_line(void *arg)
+{
+ struct fbtft_par *par = (struct fbtft_par *) arg;
+ //printk("%s\n", __func__);
+
+ /* Start sending cmd for real data transfer */
fbtft_write_init_cmd_data_transfers(par);
}
+int fbtft_write_data_window_line(struct fbtft_par *par){
+ int ret = 0;
+
+ /* Setting new line coordinates */
+ buf_ylim[0] = (write_line_start >> 8) & 0xFF;
+ buf_ylim[1] = write_line_start & 0xFF;
+ buf_ylim[2] = (write_line_end >> 8) & 0xFF;
+ buf_ylim[3] = write_line_end & 0xFF;
+
+ //printk("%s, buf[0] = %d, buf[1] = %d, buf[2] = %d, buf[3] = %d\n", __func__, buf[0], buf[1], buf[2], buf[3]);
+
+ /* Resetting to 1 for incoming data */
+ if (gpio_is_valid(par->gpio.dc))
+ gpio_set_value(par->gpio.dc, 1);
+
+ /* Start sending window_line data */
+ ret = par->fbtftops.write_async(par, buf_ylim, 4, spi_complete_data_window_line);
+ if (ret < 0)
+ dev_err(par->info->device,
+ "write() failed and returned %d\n", ret);
+
+ return ret;
+
+}
+EXPORT_SYMBOL(fbtft_write_data_window_line);
+
+
+
+
+
+
+
+
+
+
+static void spi_complete_cmd_init_data_write(void *arg)
+{
+ struct fbtft_par *par = (struct fbtft_par *) arg;
+ //printk("%s\n", __func__);
+
+ fbtft_write_vmem16_bus8_async(par, write_line_start * par->info->fix.line_length, par->length_data_transfer);
+}
+
int fbtft_write_init_cmd_data_transfers(struct fbtft_par *par){
static u8 init_data_cmd_buf = MIPI_DCS_WRITE_MEMORY_START;
int ret = 0;
//printk("%s\n", __func__);
- /* Post process */
- fbtft_post_process_screen(par, 0, par->info->var.yres-1);
-
/* Resetting to 0 for incoming cmd init data write */
if (gpio_is_valid(par->gpio.dc))
gpio_set_value(par->gpio.dc, 0);
@@ -152,37 +319,52 @@ int fbtft_write_init_cmd_data_transfers(struct fbtft_par *par){
dev_err(par->info->device,
"write() failed and returned %d\n", ret);
- /* Debug fps */
-#define FPS_DEBUG 0
-#if FPS_DEBUG
- ktime_t ts_now = ktime_get();
+ return ret;
+
+}
+EXPORT_SYMBOL(fbtft_write_init_cmd_data_transfers);
- /* First measurement */
- if (!ktime_to_ns(par->update_time))
- par->update_time = ts_now;
- long fps = ktime_us_delta(ts_now, par->update_time);
- par->update_time = ts_now;
- fps = fps ? 1000000 / fps : 0;
- if(fps){
- par->avg_fps += fps;
- par->nb_fps_values++;
- if(par->nb_fps_values == 200){
- dev_info(par->info->device,
- "Display update: fps=%ld\n", par->avg_fps/par->nb_fps_values);
- par->avg_fps = 0;
- par->nb_fps_values = 0;
- }
- }
-#endif //FPS_DEBUG
- return ret;
+
+
+
+static void spi_complete_data_write(void *arg)
+{
+ struct fbtft_par *par = (struct fbtft_par *) arg;
+ //printk("%s, par->interlacing=%d, write_line_start=%d\n", __func__, par->interlacing?1:0, write_line_start);
+
+ /* sleep */
+ //msleep(1);
+
+ if(par->interlacing){
+ /* Check if last line */
+ bool last_line = (par->odd_line && write_line_start >= par->info->var.yres-1) ||
+ (!par->odd_line && write_line_start >= par->info->var.yres-2);
+
+ if(last_line){
+ /* Start sending cmd init data */
+ par->odd_line = !par->odd_line;
+ lock = false;
+ fbtft_start_new_screen_transfer_async(par);
+ }
+ else{
+ write_line_start += 2;
+ write_line_end = write_line_start;
+
+ /* Setting window for next line */
+ fbtft_write_cmd_window_line(par);
+ }
+ }
+ else{
+ lock = false;
+ fbtft_start_new_screen_transfer_async(par);
+ }
}
-EXPORT_SYMBOL(fbtft_write_init_cmd_data_transfers);
/*****************************************************************************
*
@@ -206,8 +388,6 @@ int fbtft_write_vmem16_bus8_async(struct fbtft_par *par, size_t offset, size_t l
__func__, offset, len);
remain = len / 2;
- //vmem16 = (u16 *)(par->info->screen_buffer + offset);
- //vmem16 = (u16 *)(par->vmem_post_process + offset);
vmem16 = (u16 *)(par->vmem_ptr + offset);
if (par->gpio.dc != -1)
diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
index d576d0c..bcfa8c4 100755
--- a/drivers/staging/fbtft/fbtft-core.c
+++ b/drivers/staging/fbtft/fbtft-core.c
@@ -344,18 +344,27 @@ static void fbtft_set_addr_win(struct fbtft_par *par, int xs, int ys, int xe,
static int prev_ye = -1;
// Check if values need to be sent
- if(prev_xs!=xs || prev_ys!=ys || prev_xe!=xe || prev_ye!=ye){
+ if(prev_xs!=xs || prev_xe!=xe){
// Save prev bounding box values
prev_xs = xs;
- prev_ys = ys;
prev_xe = xe;
- prev_ye = ye;
//Set new bounding Box
+ //printk(" [%s] First write_reg: xs = %d, xe = %d\r\n", __func__, xs, xe);
write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS,
(xs >> 8) & 0xFF, xs & 0xFF, (xe >> 8) & 0xFF, xe & 0xFF);
+ }
+
+ // Check if values need to be sent
+ if(prev_ys!=ys || prev_ye!=ye){
+
+ // Save prev bounding box values
+ prev_ys = ys;
+ prev_ye = ye;
+ //Set new bounding Box
+ //printk(" [%s] 2nd write_reg: ys = %d, ye = %d\r\n", __func__, ys, ye);
write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS,
(ys >> 8) & 0xFF, ys & 0xFF, (ye >> 8) & 0xFF, ye & 0xFF);
}
@@ -539,38 +548,55 @@ static void fbtft_mkdirty(struct fb_info *info, int y, int height)
schedule_delayed_work(&info->deferred_work, fbdefio->delay);
}
-void fbtft_post_process_screen(struct fbtft_par *par, unsigned int dirty_lines_start, unsigned int dirty_lines_end){
+void fbtft_post_process_screen(struct fbtft_par *par){
int x_notif = 0;
int y_notif = 0;
bool screen_post_process = false;
- /* Reset default write buffer */
- par->vmem_ptr = par->info->screen_buffer;
+ /* bypass */
+ screen_post_process = true;
+ par->write_line_start = 0;
+ par->write_line_end = par->info->var.yres-1;
/* If soft rotation, mark whole screen to update to avoid data non rotated */
if(par->pdata->rotate_soft)
{
- dirty_lines_start = 0;
- dirty_lines_end = par->info->var.yres-1;
- par->vmem_ptr = par->vmem_post_process;
+ par->write_line_start = 0;
+ par->write_line_end = par->info->var.yres-1;
screen_post_process = true;
}
+
+ /* If notification, mark whole screen to update */
if(par->notification[0]){
- if (y_notif < dirty_lines_start)
- dirty_lines_start = y_notif;
- if (y_notif + MONACO_HEIGHT > dirty_lines_end){
- dirty_lines_end = y_notif + MONACO_HEIGHT;
- }
- par->vmem_ptr = par->vmem_post_process;
+ /*if (y_notif < par->write_line_start)
+ par->write_line_start = y_notif;
+ if (y_notif + MONACO_HEIGHT > par->write_line_end){
+ par->write_line_end = y_notif + MONACO_HEIGHT;
+ }*/
+
+ /* bypass*/
+ par->write_line_start = 0;
+ par->write_line_end = par->info->var.yres-1;
+ screen_post_process = true;
+ }
+
+ /* Low battery icon */
+ if(par->low_battery)
+ {
+ par->write_line_start = 0;
+ par->write_line_end = par->info->var.yres-1;
screen_post_process = true;
}
/* Post process */
if(screen_post_process){
+ /* Change vmem ptr to send by SPI */
+ par->vmem_ptr = par->vmem_post_process;
+
/* Copy buffer */
- memcpy(par->vmem_post_process + dirty_lines_start * par->info->fix.line_length,
- par->info->screen_buffer + dirty_lines_start * par->info->fix.line_length,
- (dirty_lines_end-dirty_lines_start+1) * par->info->fix.line_length);
+ memcpy(par->vmem_post_process + par->write_line_start * par->info->fix.line_length,
+ par->info->screen_buffer + par->write_line_start * par->info->fix.line_length,
+ (par->write_line_end-par->write_line_start+1) * par->info->fix.line_length);
/* Notifications */
if(par->notification[0]){
@@ -579,10 +605,16 @@ void fbtft_post_process_screen(struct fbtft_par *par, unsigned int dirty_lines_s
basic_text_out16_bg((u16*)par->vmem_post_process, par->info->var.xres, par->info->var.yres,
x_notif, y_notif, RGB565(255, 255, 255), RGB565(0, 0, 0), par->notification);
- if (y_notif < dirty_lines_start)
- dirty_lines_start = y_notif;
- if (y_notif + MONACO_HEIGHT > dirty_lines_end)
- dirty_lines_end = y_notif + MONACO_HEIGHT;
+ if (y_notif < par->write_line_start)
+ par->write_line_start = y_notif;
+ if (y_notif + MONACO_HEIGHT > par->write_line_end)
+ par->write_line_end = y_notif + MONACO_HEIGHT;
+ }
+
+ /* Low battery icon */
+ if(par->low_battery)
+ {
+ draw_low_battery((u16*)par->vmem_post_process, par->info->var.xres, par->info->var.yres);
}
/* Soft rotation */
@@ -602,6 +634,36 @@ static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist)
unsigned int y_low = 0, y_high = 0;
int count = 0;
+ //#define FPS_DEBUG
+ #if 0
+ long fps;
+ static ktime_t update_time;
+ static int nb_fps_values = 0;
+ static long avg_fps = 0;
+ ktime_t ts_now = ktime_get();
+
+ /* First measurement */
+ if (!ktime_to_ns(update_time))
+ update_time = ts_now;
+
+ fps = ktime_us_delta(ts_now, update_time);
+ update_time = ts_now;
+ fps = fps ? 1000000 / fps : 0;
+
+ if(fps){
+ avg_fps += fps;
+ nb_fps_values++;
+
+ if(nb_fps_values == 200){
+ fbtft_par_dbg(DEBUG_TIME_EACH_UPDATE, par,
+ "fbtft_deferred_io update: fps=%ld\n", avg_fps/nb_fps_values);
+ avg_fps = 0;
+ nb_fps_values = 0;
+ }
+ }
+
+ #endif //FPS_DEBUG
+
spin_lock(&par->dirty_lock);
dirty_lines_start = par->dirty_lines_start;
dirty_lines_end = par->dirty_lines_end;
@@ -627,10 +689,32 @@ static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist)
dirty_lines_end = y_high;
}
- fbtft_post_process_screen(par, dirty_lines_start, dirty_lines_end);
+ /* Copy buffer */
+ if(dirty_lines_start!=0 || dirty_lines_end!=par->info->var.yres - 1){
+ printk("dirty_lines_start = %d, dirty_lines_end = %d\n", dirty_lines_start, dirty_lines_end);
+ }
+ /*dirty_lines_start = 0;
+ dirty_lines_end = par->info->var.yres - 1;*/
+ par->write_line_start = dirty_lines_start;
+ par->write_line_end = dirty_lines_end;
+ memcpy(par->vmem_post_process + dirty_lines_start * par->info->fix.line_length,
+ par->info->screen_buffer + dirty_lines_start * par->info->fix.line_length,
+ (dirty_lines_end-dirty_lines_start+1) * par->info->fix.line_length);
+ par->vmem_ptr = par->vmem_post_process;
+
- /* Screen upgrade */
- par->fbtftops.update_display(par, dirty_lines_start, dirty_lines_end);
+ /* Exit in SPI async mode, otherwise update screen now */
+ if (par->spi_async_mode){
+ fbtft_start_new_screen_transfer_async(par);
+ return;
+ }
+ else{
+ /* Post process screen for doufle buf cpy, notifs, rotation soft... */
+ fbtft_post_process_screen(par);
+
+ /* Screen upgrade */
+ par->fbtftops.update_display(par, dirty_lines_start, dirty_lines_end);
+ }
}
static void fbtft_fb_fillrect(struct fb_info *info,
@@ -739,11 +823,13 @@ static int fb_deferred_io_mkwrite(struct vm_fault *vmf)
struct page *cur;
struct fbtft_par *par = info->par;
+#if 1
/* This disables fbtft's defered io, useful in spi_async mode or
if any other driver handles screens updates instead of fbtft */
if (par->spi_async_mode){
return VM_FAULT_LOCKED;
}
+#endif
/* this is a callback we get when userspace first tries to
write to the page. we schedule a workqueue. that workqueue
@@ -1101,6 +1187,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
spin_lock_init(&par->dirty_lock);
par->bgr = pdata->bgr;
par->spi_async_mode = pdata->spi_async_mode;
+ par->interlacing = pdata->interlacing;
par->startbyte = pdata->startbyte;
par->init_sequence = init_sequence;
par->gamma.curves = gamma_curves;
@@ -1262,10 +1349,12 @@ int fbtft_register_framebuffer(struct fb_info *fb_info)
sprintf(text2, ", spi%d.%d at %d MHz", spi->master->bus_num,
spi->chip_select, spi->max_speed_hz / 1000000);
dev_info(fb_info->dev,
- "%s frame buffer, %dx%d, %d KiB video memory%s, fps=%lu%s\n",
+ "%s frame buffer, %dx%d, %d KiB video memory%s, fps=%lu%s, %s%s\n",
fb_info->fix.id, fb_info->var.xres, fb_info->var.yres,
fb_info->fix.smem_len >> 10, text1,
- HZ / fb_info->fbdefio->delay, text2);
+ HZ / fb_info->fbdefio->delay, text2,
+ par->spi_async_mode?"SPI mode asynchrone, ":"",
+ par->interlacing?"Interlaced":"");
#ifdef CONFIG_FB_BACKLIGHT
/* Turn on backlight if available */
@@ -1584,6 +1673,7 @@ static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev)
pdata->rotate_soft = fbtft_of_value(node, "rotate_soft");
pdata->bgr = of_property_read_bool(node, "bgr");
pdata->spi_async_mode = of_property_read_bool(node, "spi_async_mode");
+ pdata->interlacing = of_property_read_bool(node, "interlacing");
pdata->fps = fbtft_of_value(node, "fps");
pdata->txbuflen = fbtft_of_value(node, "txbuflen");
pdata->startbyte = fbtft_of_value(node, "startbyte");
@@ -1725,7 +1815,9 @@ int fbtft_probe_common(struct fbtft_display *display,
if (par->spi_async_mode){
/* Start constant Display update using spi async*/
- fbtft_write_init_cmd_data_transfers(par);
+ par->write_line_start = 0;
+ par->write_line_end = par->info->var.yres - 1;
+ fbtft_start_new_screen_transfer_async(par);
}
return 0;
diff --git a/drivers/staging/fbtft/fbtft-io.c b/drivers/staging/fbtft/fbtft-io.c
index 1b269ee..40d31b5 100644
--- a/drivers/staging/fbtft/fbtft-io.c
+++ b/drivers/staging/fbtft/fbtft-io.c
@@ -6,7 +6,7 @@
#include "fbtft.h"
/* Ugly static declarations for now */
-#define NB_STORED_SPI_MSG 100
+#define NB_STORED_SPI_MSG 1
static int idx_spi_msg = 0;
static struct spi_transfer stored_spi_transfers[NB_STORED_SPI_MSG];
static struct spi_message stored_spi_msg[NB_STORED_SPI_MSG];
@@ -84,8 +84,9 @@ int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len)
spi_message_init(&m);
spi_message_add_tail(&t, &m);
+ //spi_sync(par->spi, &m);
return spi_sync(par->spi, &m);
- //return spi_async(par->spi, &m);
+ //return 0;
}
EXPORT_SYMBOL(fbtft_write_spi);
diff --git a/drivers/staging/fbtft/fbtft-sysfs.c b/drivers/staging/fbtft/fbtft-sysfs.c
index 5141b32..b73a26d 100644
--- a/drivers/staging/fbtft/fbtft-sysfs.c
+++ b/drivers/staging/fbtft/fbtft-sysfs.c
@@ -387,6 +387,35 @@ static ssize_t show_notification(struct device *device,
static struct device_attribute notification_device_attr =
__ATTR(notification, 0660, show_notification, store_notification);
+static ssize_t store_low_battery(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *fb_info = dev_get_drvdata(device);
+ struct fbtft_par *par = fb_info->par;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &par->low_battery);
+ if (ret)
+ return ret;
+
+ par->low_battery = par->low_battery?1:0;
+
+ return count;
+}
+
+static ssize_t show_low_battery(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *fb_info = dev_get_drvdata(device);
+ struct fbtft_par *par = fb_info->par;
+
+ return snprintf(buf, PAGE_SIZE, "%lu\n", par->low_battery);
+}
+
+static struct device_attribute low_battery_device_attr =
+ __ATTR(low_battery, 0660, show_low_battery, store_low_battery);
+
void fbtft_expand_debug_value(unsigned long *debug)
{
switch (*debug & 0x7) {
@@ -448,6 +477,7 @@ static ssize_t show_debug(struct device *device,
void fbtft_sysfs_init(struct fbtft_par *par)
{
device_create_file(par->info->dev, &debug_device_attr);
+ device_create_file(par->info->dev, &low_battery_device_attr);
device_create_file(par->info->dev, &rotate_soft_device_attr);
device_create_file(par->info->dev, &notification_device_attr);
device_create_file(par->info->dev, &overlay_device_attrs[0]);
@@ -458,6 +488,7 @@ void fbtft_sysfs_init(struct fbtft_par *par)
void fbtft_sysfs_exit(struct fbtft_par *par)
{
device_remove_file(par->info->dev, &debug_device_attr);
+ device_remove_file(par->info->dev, &low_battery_device_attr);
device_remove_file(par->info->dev, &rotate_soft_device_attr);
device_remove_file(par->info->dev, &notification_device_attr);
device_remove_file(par->info->dev, &overlay_device_attrs[0]);
diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h
index e6b4c59..64dec83 100644
--- a/drivers/staging/fbtft/fbtft.h
+++ b/drivers/staging/fbtft/fbtft.h
@@ -154,6 +154,7 @@ struct fbtft_platform_data {
unsigned long rotate_soft;
bool bgr;
bool spi_async_mode;
+ bool interlacing;
unsigned int fps;
int txbuflen;
u8 startbyte;
@@ -252,13 +253,22 @@ struct fbtft_par {
} overlay;
char notification[FBTFT_NOTIF_MAX_SIZE+1];
unsigned long debug;
+ unsigned long low_battery;
bool first_update_done;
ktime_t update_time;
long avg_fps;
int nb_fps_values;
bool bgr;
void *extra;
+
+ /* SPI async */
bool spi_async_mode;
+ bool interlacing;
+ bool odd_line;
+ int cur_line;
+ int write_line_start;
+ int write_line_end;
+ u32 length_data_transfer;
};
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
@@ -283,8 +293,7 @@ int fbtft_probe_common(struct fbtft_display *display, struct spi_device *sdev,
struct platform_device *pdev);
int fbtft_remove_common(struct device *dev, struct fb_info *info);
void fbtft_rotate_soft(u16 *mat, int size, int rotation);
-void fbtft_post_process_screen(struct fbtft_par *par,
- unsigned int dirty_lines_start, unsigned int dirty_lines_end);
+void fbtft_post_process_screen(struct fbtft_par *par);
/* fbtft-io.c */
int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len);
@@ -296,6 +305,9 @@ void fbtft_post_process_screen(struct fbtft_par *par,
int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len);
/* fbtft-bus.c */
+int fbtft_start_new_screen_transfer_async(struct fbtft_par *par);
+int fbtft_write_cmd_window_line(struct fbtft_par *par);
+int fbtft_write_data_window_line(struct fbtft_par *par);
int fbtft_write_init_cmd_data_transfers(struct fbtft_par *par);
int fbtft_write_vmem8_bus8(struct fbtft_par *par, size_t offset, size_t len);
int fbtft_write_vmem16_bus16(struct fbtft_par *par, size_t offset, size_t len);
--
1.9.1

View File

@ -1,75 +0,0 @@
From 2505384b62b599da8cf234a14bdbab54f603083b Mon Sep 17 00:00:00 2001
From: vincent <vbusoenseirb@gmail.com>
Date: Wed, 19 Feb 2020 08:32:46 +0100
Subject: [PATCH] changed battery logo
---
drivers/staging/fbtft/fb_text.c | 47 ++++++++++++++++++-----------------------
1 file changed, 21 insertions(+), 26 deletions(-)
diff --git a/drivers/staging/fbtft/fb_text.c b/drivers/staging/fbtft/fb_text.c
index 650535d..b1ecdd4 100644
--- a/drivers/staging/fbtft/fb_text.c
+++ b/drivers/staging/fbtft/fb_text.c
@@ -4,37 +4,32 @@
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
-#define LOW_BATTERY_ICON_TOP_LEFT_X 10
-#define LOW_BATTERY_ICON_TOP_LEFT_Y 10
-#define LOW_BATTERY_ICON_WIDTH 35
-#define LOW_BATTERY_ICON_HEIGHT 20
+#define LOW_BATTERY_ICON_WIDTH 34
+#define LOW_BATTERY_ICON_HEIGHT 16
+#define LOW_BATTERY_ICON_TOP_LEFT_X (240-LOW_BATTERY_ICON_WIDTH-5)
+#define LOW_BATTERY_ICON_TOP_LEFT_Y (13 - LOW_BATTERY_ICON_HEIGHT/2)
//#define LOW_BATTERY_FORE_COLOR 65535
#define LOW_BATTERY_FORE_COLOR 0xF800
#define LOW_BATTERY_BACK_COLOR 0
-// Battery icon from: https://github.com/martinohanlon/grrl-bat-monitor
-static u16 lowBatteryIcon [LOW_BATTERY_ICON_HEIGHT][LOW_BATTERY_ICON_WIDTH] = {
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
- {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
- {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
- {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
- {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
- {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
- {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0},
- {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0},
- {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0},
- {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0},
- {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
- {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
- {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
- {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
- {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
- {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0},
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+static uint32_t lowBatteryIcon [LOW_BATTERY_ICON_HEIGHT][LOW_BATTERY_ICON_WIDTH] = {
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0},
+ {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0},
+ {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0},
+ {0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0},
+ {0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0},
+ {0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0},
+ {0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0},
+ {0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0},
+ {0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0},
+ {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0},
+ {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0},
+ {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
--
1.9.1

File diff suppressed because it is too large Load Diff

View File

@ -1,394 +0,0 @@
From fc4a5c2f32f088e23d0078d2e1867ed6708b66f3 Mon Sep 17 00:00:00 2001
From: vincent <vbusoenseirb@gmail.com>
Date: Sat, 26 Sep 2020 02:11:52 +0200
Subject: [PATCH] fbtft with TE working
---
arch/arm/boot/dts/sun8i-v3s-funkey.dts | 1 +
drivers/staging/fbtft/fb_st7789v.c | 10 ++-
drivers/staging/fbtft/fbtft-bus.c | 22 ++++--
drivers/staging/fbtft/fbtft-core.c | 128 ++++++++++++++++++++++++++-------
drivers/staging/fbtft/fbtft.h | 3 +
5 files changed, 129 insertions(+), 35 deletions(-)
diff --git a/arch/arm/boot/dts/sun8i-v3s-funkey.dts b/arch/arm/boot/dts/sun8i-v3s-funkey.dts
index 20f9913..24e26b2 100644
--- a/arch/arm/boot/dts/sun8i-v3s-funkey.dts
+++ b/arch/arm/boot/dts/sun8i-v3s-funkey.dts
@@ -186,6 +186,7 @@
buswidth = <8>;
reset-gpios = <&pio 1 2 GPIO_ACTIVE_HIGH>; //PB2
dc-gpios = <&pio 2 0 GPIO_ACTIVE_LOW>; //PC0 (MISO)
+ te-irq = <&pio 1 1 GPIO_ACTIVE_LOW>; //PB1
debug = <0>;
};
};
diff --git a/drivers/staging/fbtft/fb_st7789v.c b/drivers/staging/fbtft/fb_st7789v.c
index e2c9078..f33f8e3 100755
--- a/drivers/staging/fbtft/fb_st7789v.c
+++ b/drivers/staging/fbtft/fb_st7789v.c
@@ -52,6 +52,8 @@
* out as well to avoid duplicate entries.
*/
enum st7789v_command {
+ TEOFF = 0x34,
+ TEON = 0x35,
PORCTRL = 0xB2,
GCTRL = 0xB7,
VCOMS = 0xBB,
@@ -153,10 +155,14 @@ static int init_display(struct fbtft_par *par)
/* Display Inversion of colors */
write_reg(par, 0x21);
+ /* Activate TE signal for Vsync only */
+ write_reg(par, TEON, 0x00);
+
/* refresh rate */
//write_reg(par, 0xC6,0x1F); //39Hz
//write_reg(par, 0xC6,0x1A); //44Hz
- //write_reg(par, 0xC6,0x17); //48Hz
+ //write_reg(par, 0xC6,0x18); //46Hz
+ write_reg(par, 0xC6,0x17); //48Hz
//write_reg(par, 0xC6,0x16); //49Hz
//write_reg(par, 0xC6,0x15); //50Hz
//write_reg(par, 0xC6,0x14); //52Hz
@@ -165,7 +171,7 @@ static int init_display(struct fbtft_par *par)
//write_reg(par, 0xC6,0x0F); //60Hz
//write_reg(par, 0xC6,0x09); //60Hz
//write_reg(par, 0xC6,0x03); //99Hz
- write_reg(par, 0xC6,0x02); //105Hz
+ //write_reg(par, 0xC6,0x02); //105Hz -> good one when no TE signal
write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
diff --git a/drivers/staging/fbtft/fbtft-bus.c b/drivers/staging/fbtft/fbtft-bus.c
index ce865ed..801cdf4 100644
--- a/drivers/staging/fbtft/fbtft-bus.c
+++ b/drivers/staging/fbtft/fbtft-bus.c
@@ -124,6 +124,10 @@ void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...)
int fbtft_start_new_screen_transfer_async(struct fbtft_par *par){
//printk("%s\n", __func__);
+ if(par->pdata->te_irq && !par->ready_for_spi_async){
+ return -1;
+ }
+
if(lock){
return -1;
}
@@ -135,8 +139,8 @@ int fbtft_start_new_screen_transfer_async(struct fbtft_par *par){
}*/
/* Debug fps */
-#define FPS_DEBUG 1
-#if FPS_DEBUG
+//#define FPS_DEBUG
+#ifdef FPS_DEBUG
long fps;
ktime_t ts_now = ktime_get();
@@ -153,13 +157,13 @@ int fbtft_start_new_screen_transfer_async(struct fbtft_par *par){
par->nb_fps_values++;
if(par->nb_fps_values == 200){
- fbtft_par_dbg(DEBUG_TIME_EACH_UPDATE, par,
- "Display update: fps=%ld\n", par->avg_fps/par->nb_fps_values);
+ /*fbtft_par_dbg(DEBUG_TIME_EACH_UPDATE, par,
+ "Display update: fps=%ld\n", par->avg_fps/par->nb_fps_values);*/
+ printk("Display update: fps=%ld\n", par->avg_fps/par->nb_fps_values);
par->avg_fps = 0;
par->nb_fps_values = 0;
}
}
-
#endif //FPS_DEBUG
/* Post process screen for doufle buf cpy, notifs, rotation soft... */
@@ -350,7 +354,9 @@ static void spi_complete_data_write(void *arg)
/* Start sending cmd init data */
par->odd_line = !par->odd_line;
lock = false;
- fbtft_start_new_screen_transfer_async(par);
+ if(!par->pdata->te_irq){
+ fbtft_start_new_screen_transfer_async(par);
+ }
}
else{
write_line_start += 2;
@@ -362,7 +368,9 @@ static void spi_complete_data_write(void *arg)
}
else{
lock = false;
- fbtft_start_new_screen_transfer_async(par);
+ if(!par->pdata->te_irq){
+ fbtft_start_new_screen_transfer_async(par);
+ }
}
}
diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
index bcfa8c4..b362bc0 100755
--- a/drivers/staging/fbtft/fbtft-core.c
+++ b/drivers/staging/fbtft/fbtft-core.c
@@ -37,6 +37,7 @@
#include <video/mipi_display.h>
#include <linux/hrtimer.h>
#include <linux/list.h>
+#include <linux/interrupt.h>
/* to support deferred IO */
#include <linux/rmap.h>
@@ -432,12 +433,16 @@ static void fbtft_update_display(struct fbtft_par *par, unsigned int start_line,
fbtft_par_dbg(DEBUG_UPDATE_DISPLAY, par, "%s(start_line=%u, end_line=%u)\n",
__func__, start_line, end_line);
- par->fbtftops.set_addr_win(par, 0, start_line,
- par->info->var.xres - 1, end_line);
- /*if (par->fbtftops.set_addr_win){
+
+ if(par->pdata->rotate == 90){
par->fbtftops.set_addr_win(par, 80, start_line,
- 320 - 1, end_line);
- }*/
+ 320 - 1, end_line);
+ }
+ else{
+ par->fbtftops.set_addr_win(par, 0, start_line,
+ par->info->var.xres - 1, end_line);
+ }
+
}
/* Send cmd to start transfer */
@@ -500,7 +505,7 @@ void fbtft_rotate_soft(u16 *mat, int size, int rotation){
mat[AT(i, j)] = mat[AT(N - 1 - j, i)];
mat[AT(N - 1 - j, i)] = mat[AT(N - 1 - i, N - 1 - j)];
mat[AT(N - 1 - i, N - 1 - j)] = mat[AT(j, N - 1 - i)];
- mat[AT(j, N - 1 - i)] = temp;
+ mat[AT(j, N - 1 - i)] = temp;
}
}
}
@@ -524,7 +529,7 @@ static void fbtft_mkdirty(struct fb_info *info, int y, int height)
struct fbtft_par *par = info->par;
struct fb_deferred_io *fbdefio = info->fbdefio;
- /* This disables fbtft's defered io, useful in spi_asyn mode or
+ /* This disables fbtft's defered io, useful in spi_async mode or
if any other driver handles screens updates instead of fbtft */
if (par->spi_async_mode){
return;
@@ -554,9 +559,12 @@ void fbtft_post_process_screen(struct fbtft_par *par){
bool screen_post_process = false;
/* bypass */
+//#define FORCE_POSTPROCESS
+#ifdef FORCE_POSTPROCESS
screen_post_process = true;
par->write_line_start = 0;
par->write_line_end = par->info->var.yres-1;
+#endif //FORCE_POSTPROCESS
/* If soft rotation, mark whole screen to update to avoid data non rotated */
if(par->pdata->rotate_soft)
@@ -594,6 +602,15 @@ void fbtft_post_process_screen(struct fbtft_par *par){
par->vmem_ptr = par->vmem_post_process;
/* Copy buffer */
+ /* This should be handled using a double buffer (or triple depending on game fps vs screen fps) */
+ /* pointed by par->info->screen_buffer. The buffer pointed (the one being written) should */
+ /* change using the FBIOPAN_DISPLAY ioctl called by SDL_Flip() (in FB_FlipHWSurface) */
+ /* This is a dirty but very efficient alternative for now: we make a quick memcpy of the */
+ /* screen_buffer in another one. It goes so fast that the "applicative" */
+ /* tearing that could happen if this function were to launch in the middle of a */
+ /* user space SDL_BlitSurface(sw_surface, NULL, hw_surface, NULL) call */
+ /* is so unbelievably rare that completey unnoticeable and it takes up so little CPU */
+ /* that really, it's worth the compromise for now */
memcpy(par->vmem_post_process + par->write_line_start * par->info->fix.line_length,
par->info->screen_buffer + par->write_line_start * par->info->fix.line_length,
(par->write_line_end-par->write_line_start+1) * par->info->fix.line_length);
@@ -623,6 +640,9 @@ void fbtft_post_process_screen(struct fbtft_par *par){
fbtft_rotate_soft((u16*)par->vmem_post_process, par->info->var.yres, par->pdata->rotate_soft);
}
}
+ else{
+ par->vmem_ptr = par->info->screen_buffer;
+ }
}
static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist)
@@ -690,31 +710,19 @@ static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist)
}
/* Copy buffer */
- if(dirty_lines_start!=0 || dirty_lines_end!=par->info->var.yres - 1){
+ /*if(dirty_lines_start!=0 || dirty_lines_end!=par->info->var.yres - 1){
printk("dirty_lines_start = %d, dirty_lines_end = %d\n", dirty_lines_start, dirty_lines_end);
- }
+ }*/
/*dirty_lines_start = 0;
dirty_lines_end = par->info->var.yres - 1;*/
par->write_line_start = dirty_lines_start;
par->write_line_end = dirty_lines_end;
- memcpy(par->vmem_post_process + dirty_lines_start * par->info->fix.line_length,
- par->info->screen_buffer + dirty_lines_start * par->info->fix.line_length,
- (dirty_lines_end-dirty_lines_start+1) * par->info->fix.line_length);
- par->vmem_ptr = par->vmem_post_process;
+ /* Post process screen for doufle buf cpy, notifs, rotation soft... */
+ fbtft_post_process_screen(par);
- /* Exit in SPI async mode, otherwise update screen now */
- if (par->spi_async_mode){
- fbtft_start_new_screen_transfer_async(par);
- return;
- }
- else{
- /* Post process screen for doufle buf cpy, notifs, rotation soft... */
- fbtft_post_process_screen(par);
-
- /* Screen upgrade */
- par->fbtftops.update_display(par, dirty_lines_start, dirty_lines_end);
- }
+ /* Screen upgrade */
+ par->fbtftops.update_display(par, dirty_lines_start, dirty_lines_end);
}
static void fbtft_fb_fillrect(struct fb_info *info,
@@ -1182,11 +1190,13 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
par->vmem_post_process = vmem_post_process;
par->vmem_ptr = par->info->screen_buffer;
par->pdata = pdata;
+ pdata->par = par;
par->debug = display->debug;
par->buf = buf;
spin_lock_init(&par->dirty_lock);
par->bgr = pdata->bgr;
par->spi_async_mode = pdata->spi_async_mode;
+ par->ready_for_spi_async = false;
par->interlacing = pdata->interlacing;
par->startbyte = pdata->startbyte;
par->init_sequence = init_sequence;
@@ -1648,10 +1658,40 @@ static u32 fbtft_of_value(struct device_node *node, const char *propname)
return val;
}
+
+static irqreturn_t irq_TE_handler(int irq_no, void *dev_id)
+{
+ struct fbtft_platform_data *pdata = (struct fbtft_platform_data *) dev_id;
+
+//#define DEBUG_TE_IRQ_COUNT
+#ifdef DEBUG_TE_IRQ_COUNT
+ static ktime_t prev_ts = 0;
+ static int te_count = 0;
+ static int nb_sec = 5;
+ te_count++;
+
+ ktime_t ts_now = ktime_get();
+ if(ktime_us_delta(ts_now, prev_ts) > nb_sec*1000000){
+ prev_ts = ts_now;
+ printk("TE irq: %d times/sec\n", te_count/nb_sec);
+ te_count = 0;
+ }
+#endif //DEBUG_TE_IRQ_COUNT
+
+ fbtft_start_new_screen_transfer_async(pdata->par);
+
+ return IRQ_HANDLED;
+}
+
+
+
static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev)
{
struct device_node *node = dev->of_node;
struct fbtft_platform_data *pdata;
+ int gpio, irq_id, err;
+ enum of_gpio_flags of_flags;
+ char *te_irq_name;
if (!node) {
dev_err(dev, "Missing platform data or DT\n");
@@ -1685,6 +1725,37 @@ static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev)
pdata->display.fbtftops.init_display = fbtft_init_display_dt;
pdata->display.fbtftops.request_gpios = fbtft_request_gpios_dt;
+ /* TE signal for Vsync */
+ pdata->te_irq = false;
+ te_irq_name = "te-irq";
+ if (of_find_property(node, te_irq_name, NULL)) {
+ gpio = of_get_named_gpio_flags(node, te_irq_name, 0, &of_flags);
+ if (gpio == -ENOENT || gpio == -EPROBE_DEFER || gpio < 0) {
+ dev_err(dev,
+ "failed to get '%s' from DT\n", te_irq_name);
+ }
+ else{
+ pr_info("%s: '%s' = GPIO%d\n", __func__, te_irq_name, gpio);
+
+ irq_id = gpio_to_irq(gpio);
+ if(irq_id < 0) {
+ dev_err(dev,"%s - Unable to request IRQ: %d\n", __func__, irq_id);
+ }
+ else{
+ pr_info("TE GPIO%d, IRQ id = %d\n", gpio, irq_id);
+
+ err = request_irq(irq_id, irq_TE_handler, IRQF_SHARED | IRQF_TRIGGER_RISING,
+ "TE", pdata);
+ if (err < 0) {
+ dev_err(dev,"ERROR initializing TE signal irq\n");
+ }
+ else{
+ pdata->te_irq = true;
+ }
+ }
+ }
+ }
+
return pdata;
}
#else
@@ -1817,7 +1888,12 @@ int fbtft_probe_common(struct fbtft_display *display,
/* Start constant Display update using spi async*/
par->write_line_start = 0;
par->write_line_end = par->info->var.yres - 1;
- fbtft_start_new_screen_transfer_async(par);
+ if(par->pdata->te_irq){
+ par->ready_for_spi_async = true;
+ }
+ else{
+ fbtft_start_new_screen_transfer_async(par);
+ }
}
return 0;
diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h
index 64dec83..8a9daee 100644
--- a/drivers/staging/fbtft/fbtft.h
+++ b/drivers/staging/fbtft/fbtft.h
@@ -154,12 +154,14 @@ struct fbtft_platform_data {
unsigned long rotate_soft;
bool bgr;
bool spi_async_mode;
+ bool te_irq;
bool interlacing;
unsigned int fps;
int txbuflen;
u8 startbyte;
char *gamma;
void *extra;
+ struct fbtft_par *par;
};
/**
@@ -263,6 +265,7 @@ struct fbtft_par {
/* SPI async */
bool spi_async_mode;
+ bool ready_for_spi_async;
bool interlacing;
bool odd_line;
int cur_line;
--
1.9.1

View File

@ -1,45 +0,0 @@
From 709159a6428f696915df4ff9795af86ddc328740 Mon Sep 17 00:00:00 2001
From: vincent <vbusoenseirb@gmail.com>
Date: Mon, 28 Sep 2020 15:05:59 +0200
Subject: [PATCH] battery charge current set to 400mA
---
arch/arm/boot/dts/sun8i-v3s-funkey.dts | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/sun8i-v3s-funkey.dts b/arch/arm/boot/dts/sun8i-v3s-funkey.dts
index 24e26b2..ffff865 100644
--- a/arch/arm/boot/dts/sun8i-v3s-funkey.dts
+++ b/arch/arm/boot/dts/sun8i-v3s-funkey.dts
@@ -63,6 +63,11 @@
default-brightness-level = <11>;
power-supply = <&reg_vcc5v0>;
};
+
+ bat: battery {
+ compatible = "simple-battery";
+ constant_charge_current_max_microamp = <400000>;
+ };
};
&codec {
@@ -121,6 +126,7 @@
&battery_power_supply {
status = "okay";
+ monitored-battery = <&bat>;
};
&usb_power_supply {
@@ -177,7 +183,7 @@
reg = <0>;
spi-max-frequency = <50000000>;
txbuflen = <115202>;
-// txbuflen = <0>;
+ //txbuflen = <0>;
spi_async_mode = "true";
//interlacing = "true";
rotate = <0>;
--
1.9.1

View File

@ -1,25 +0,0 @@
From 4e80937d23c58478e8a3ffe3a5cdb4114497c638 Mon Sep 17 00:00:00 2001
From: vincent <vbusoenseirb@gmail.com>
Date: Tue, 29 Sep 2020 08:32:44 +0200
Subject: [PATCH] increasd buffer size for fb_tft_notif zone to 400
---
drivers/staging/fbtft/fbtft.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h
index 8a9daee..4638ad9 100644
--- a/drivers/staging/fbtft/fbtft.h
+++ b/drivers/staging/fbtft/fbtft.h
@@ -28,7 +28,7 @@
#define FBTFT_GAMMA_MAX_VALUES_TOTAL 128
#define FBTFT_OVERLAY_NB_VALUES 4
-#define FBTFT_NOTIF_MAX_SIZE 256
+#define FBTFT_NOTIF_MAX_SIZE 400
#define FBTFT_OF_INIT_CMD BIT(24)
#define FBTFT_OF_INIT_DELAY BIT(25)
--
1.9.1

View File

@ -1,207 +0,0 @@
/*
* Copyright (C) 2019 Michel Stempin <michel.stempin@wanadoo.fr>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
* licensing only applies to this file, and not this project as a
* whole.
*
* a) This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Or, alternatively,
*
* b) Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
#include "sun8i-v3s.dtsi"
#include "sunxi-common-regulators.dtsi"
/ {
model = "FunKey";
compatible = "funkey", "allwinner,sun8i-v3s";
aliases {
serial0 = &uart0;
};
chosen {
stdout-path = "serial0:115200n8";
};
backlight: backlight {
compatible = "pwm-backlight";
pwms = <&pwm 0 1000000 0>;
brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
default-brightness-level = <10>;
power-supply = <&reg_vcc5v0>;
};
};
&codec {
allwinner,audio-routing =
"Headphone", "HP",
"Headphone", "HPCOM",
"MIC1", "Mic",
"Mic", "HBIAS";
status = "okay";
};
&ehci0 {
status = "okay";
};
&i2c0 {
status = "okay";
axp209: pmic@34 {
compatible = "x-powers,axp209";
reg = <0x34>;
interrupt-parent = <&pio>;
interrupts = <1 5 IRQ_TYPE_EDGE_FALLING>;
interrupt-controller;
#interrupt-cells = <1>;
};
};
&mmc0 {
pinctrl-0 = <&mmc0_pins_a>;
pinctrl-names = "default";
broken-cd;
bus-width = <4>;
vmmc-supply = <&reg_vcc3v3>;
vqmmc-supply = <&reg_vcc3v3>;
status = "okay";
};
&ohci0 {
status = "okay";
};
#include "axp209.dtsi"
&ac_power_supply {
status = "okay";
};
&axp_gpio {
status = "okay";
};
&battery_power_supply {
status = "okay";
};
&usb_power_supply {
status = "okay";
};
&reg_dcdc2 {
regulator-always-on;
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1400000>;
regulator-name = "vdd-cpu-sys-ephy";
};
&reg_dcdc3 {
regulator-always-on;
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3450000>;
regulator-name = "vcc-io-ephy-mcsi-usb";
};
&reg_ldo1 {
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3600000>;
regulator-name = "vcc-rtc";
};
&reg_ldo2 {
regulator-always-on;
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <3300000>;
regulator-name = "avcc-pll";
};
&reg_vcc3v0 {
regulator-always-on;
status = "okay";
};
&reg_vcc3v3 {
regulator-always-on;
status = "okay";
};
&reg_vcc5v0 {
regulator-always-on;
status = "okay";
};
&spi0 {
status = "okay";
st7789v@0 {
compatible = "sitronix,st7789v";
reg = <0>;
spi-max-frequency = <40000000>;
txbuflen = <115200>;
rotate = <0>;
fps = <39>;
buswidth = <8>;
reset-gpios = <&pio 4 1 GPIO_ACTIVE_LOW>; //PE1
dc-gpios = <&pio 2 0 GPIO_ACTIVE_LOW>; //PC0 (MISO)
debug = <0>;
};
};
&uart0 {
pinctrl-0 = <&uart0_pins_a>;
pinctrl-names = "default";
status = "okay";
};
&pwm {
pinctrl-names = "default";
pinctrl-0 = <&pwm0_pins>;
status = "okay";
};
&usb_otg {
dr_mode = "peripheral";
status = "okay";
};
&usbphy {
usb0_vbus-supply = <&reg_vcc5v0>;
phy-supply = <&reg_vcc5v0>;
vcc = <&reg_vcc5v0>;
status = "okay";
};

View File

@ -19,7 +19,7 @@ BR2_ROOTFS_POST_SCRIPT_ARGS="-c $(BR2_EXTERNAL_FUNKEY_PATH)/board/funkey/genimag
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_GIT=y
BR2_LINUX_KERNEL_CUSTOM_REPO_URL="https://github.com/FunKey-Project/linux"
BR2_LINUX_KERNEL_CUSTOM_REPO_VERSION="cda44c146b9b87290bc7c636ffa7d88cbfb03ace"
BR2_LINUX_KERNEL_CUSTOM_REPO_VERSION="932bc41a1a2ce477855240d39edbf7a9af5b7490"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(BR2_EXTERNAL_FUNKEY_PATH)/board/funkey/linux.config"
BR2_LINUX_KERNEL_LZO=y