Updated and fixed ST7789v driver

This commit is contained in:
Melissa LeBlanc-Williams 2023-05-26 17:06:41 -07:00
parent d49b6e9d95
commit 97a7d43e85
7 changed files with 221 additions and 43 deletions

View file

@ -275,11 +275,6 @@ def is_kernel_upgrade_required(config = None):
config = pitft_config config = pitft_config
if not config['kernel_upgrade']: if not config['kernel_upgrade']:
return False return False
module = config['kernel_module']
if shell.exists(f"/lib/modules/{shell.release()}/kernel/drivers/staging/fbtft/{module}.ko.xz"):
return False
if shell.exists(f"/lib/modules/{shell.release()}/kernel/drivers/staging/fbtft/{module}.ko"):
return False
return True return True
@ -309,11 +304,10 @@ def install_drivers():
shell.pushd("st7789_module") shell.pushd("st7789_module")
if not shell.run_command("make"): if not shell.run_command("make"):
warn_exit("Apt failed to compile ST7789V drivers!") warn_exit("Apt failed to compile ST7789V drivers!")
shell.run_command(f"mv /lib/modules/{shell.release()}/kernel/drivers/staging/fbtft/{module}.ko /lib/modules/{shell.release()}/kernel/drivers/staging/fbtft/{module}.BACK") shell.run_command(f"mv /lib/modules/{shell.release()}/kernel/drivers/staging/fbtft/{module}.ko.xz /lib/modules/{shell.release()}/kernel/drivers/staging/fbtft/{module}.BACK.xz")
shell.run_command(f"mv {module}.ko /lib/modules/{shell.release()}/kernel/drivers/staging/fbtft/{module}.ko") shell.run_command(f"xz -v2 {module}.ko")
shell.run_command(f"mv {module}.ko.xz /lib/modules/{shell.release()}/kernel/drivers/staging/fbtft/{module}.ko.xz")
shell.popd() shell.popd()
# We may need to unzip the /lib/modules/6.1.19-v8+/kernel/drivers/staging/fbtft/fb_st7789v.ko.xz file
return True return True
def update_configtxt(rotation_override=None): def update_configtxt(rotation_override=None):
@ -759,4 +753,5 @@ restart the script and choose a different orientation.""".format(rotation=pitftr
# Main function # Main function
if __name__ == "__main__": if __name__ == "__main__":
shell.require_root() shell.require_root()
shell.check_kernel_userspace_mismatch()
main() main()

View file

@ -43,7 +43,7 @@
#size-cells = <0>; #size-cells = <0>;
pitft: pitft@0{ pitft: pitft@0{
compatible = "sitronix,st7789v"; compatible = "fbtft,minipitft13";
reg = <0>; reg = <0>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&pitft_pins>; pinctrl-0 = <&pitft_pins>;

View file

@ -43,7 +43,7 @@
#size-cells = <0>; #size-cells = <0>;
pitft: pitft@0{ pitft: pitft@0{
compatible = "sitronix,st7789v"; compatible = "fbtft,minipitft13";
reg = <0>; reg = <0>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&pitft_pins>; pinctrl-0 = <&pitft_pins>;

View file

@ -43,7 +43,7 @@
#size-cells = <0>; #size-cells = <0>;
pitft: pitft@0{ pitft: pitft@0{
compatible = "sitronix,st7789v"; compatible = "fbtft,minipitft13";
reg = <0>; reg = <0>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&pitft_pins>; pinctrl-0 = <&pitft_pins>;

View file

@ -7,9 +7,13 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/module.h> #include <linux/module.h>
#include <video/mipi_display.h> #include <video/mipi_display.h>
#include "fbtft.h" #include "fbtft.h"
@ -66,13 +70,68 @@ enum st7789v_command {
#define MADCTL_MX BIT(6) /* bitmask for column address order */ #define MADCTL_MX BIT(6) /* bitmask for column address order */
#define MADCTL_MY BIT(7) /* bitmask for page address order */ #define MADCTL_MY BIT(7) /* bitmask for page address order */
static u32 col1_offset = 0; /* 60Hz for 16.6ms, configured as 2*16.6ms */
static u32 col2_offset = 0; #define PANEL_TE_TIMEOUT_MS 33
static u32 row1_offset = 0;
static u32 row2_offset = 0; static struct completion panel_te; /* completion for panel TE line */
static int irq_te; /* Linux IRQ for LCD TE line */
static u32 col_start_offset = 0;
static u32 col_end_offset = 0;
static u32 row_start_offset = 0;
static u32 row_end_offset = 0;
static short x_offset = 0; static short x_offset = 0;
static short y_offset = 0; static short y_offset = 0;
static irqreturn_t panel_te_handler(int irq, void *data)
{
complete(&panel_te);
return IRQ_HANDLED;
}
/*
* init_tearing_effect_line() - init tearing effect line.
* @par: FBTFT parameter object.
*
* Return: 0 on success, or a negative error code otherwise.
*/
static int init_tearing_effect_line(struct fbtft_par *par)
{
struct device *dev = par->info->device;
struct gpio_desc *te;
int rc, irq;
te = gpiod_get_optional(dev, "te", GPIOD_IN);
if (IS_ERR(te))
return dev_err_probe(dev, PTR_ERR(te), "Failed to request te GPIO\n");
/* if te is NULL, indicating no configuration, directly return success */
if (!te) {
irq_te = 0;
return 0;
}
irq = gpiod_to_irq(te);
/* GPIO is locked as an IRQ, we may drop the reference */
gpiod_put(te);
if (irq < 0)
return irq;
irq_te = irq;
init_completion(&panel_te);
/* The effective state is high and lasts no more than 1000 microseconds */
rc = devm_request_irq(dev, irq_te, panel_te_handler,
IRQF_TRIGGER_RISING, "TE_GPIO", par);
if (rc)
return dev_err_probe(dev, rc, "TE IRQ request failed.\n");
disable_irq_nosync(irq_te);
return 0;
}
/** /**
* init_display() - initialize the display controller * init_display() - initialize the display controller
* *
@ -89,6 +148,14 @@ static short y_offset = 0;
*/ */
static int init_display(struct fbtft_par *par) static int init_display(struct fbtft_par *par)
{ {
int rc;
par->fbtftops.reset(par);
rc = init_tearing_effect_line(par);
if (rc)
return rc;
/* turn off sleep mode */ /* turn off sleep mode */
write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE); write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE);
mdelay(120); mdelay(120);
@ -144,6 +211,10 @@ static int init_display(struct fbtft_par *par)
*/ */
write_reg(par, PWCTRL1, 0xA4, 0xA1); write_reg(par, PWCTRL1, 0xA4, 0xA1);
/* TE line output is off by default when powering on */
if (irq_te)
write_reg(par, MIPI_DCS_SET_TEAR_ON, 0x00);
write_reg(par, MIPI_DCS_SET_DISPLAY_ON); write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
if (HSD20_IPS) if (HSD20_IPS)
@ -152,7 +223,51 @@ static int init_display(struct fbtft_par *par)
return 0; return 0;
} }
static void minipitft_set_addr_win(struct fbtft_par *par, int xs, int ys, /*
* write_vmem() - write data to display.
* @par: FBTFT parameter object.
* @offset: offset from screen_buffer.
* @len: the length of data to be writte.
*
* Return: 0 on success, or a negative error code otherwise.
*/
static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
{
struct device *dev = par->info->device;
int ret;
if (irq_te) {
enable_irq(irq_te);
reinit_completion(&panel_te);
ret = wait_for_completion_timeout(&panel_te,
msecs_to_jiffies(PANEL_TE_TIMEOUT_MS));
if (ret == 0)
dev_err(dev, "wait panel TE timeout\n");
disable_irq(irq_te);
}
switch (par->pdata->display.buswidth) {
case 8:
ret = fbtft_write_vmem16_bus8(par, offset, len);
break;
case 9:
ret = fbtft_write_vmem16_bus9(par, offset, len);
break;
case 16:
ret = fbtft_write_vmem16_bus16(par, offset, len);
break;
default:
dev_err(dev, "Unsupported buswidth %d\n",
par->pdata->display.buswidth);
ret = 0;
break;
}
return ret;
}
static void minipitft13_set_addr_win(struct fbtft_par *par, int xs, int ys,
int xe, int ye) int xe, int ye)
{ {
xs += x_offset; xs += x_offset;
@ -185,35 +300,36 @@ static int set_var(struct fbtft_par *par)
madctl_par |= MADCTL_BGR; madctl_par |= MADCTL_BGR;
if (width < 240) { if (width < 240) {
// Display is centered // Smaller displays are centered
row1_offset = row2_offset = (int)((320 - height + 1) / 2); row_start_offset = row_end_offset = (int)((320 - height + 1) / 2);
col1_offset = (int)((240 - width) / 2); col_start_offset = (int)((240 - width) / 2);
col2_offset = (int)((240 - width + 1) / 2); col_end_offset = (int)((240 - width + 1) / 2); // Account for extra pixel
} else { } else {
row1_offset = 0; // Larger displays are left-aligned
row2_offset = (320 - height); row_start_offset = 0;
col1_offset = col2_offset = (240 - width); row_end_offset = (320 - height);
col_start_offset = col_end_offset = 0;
} }
switch (par->info->var.rotate) { switch (par->info->var.rotate) {
case 0: case 0:
x_offset = col1_offset; x_offset = col_start_offset;
y_offset = row1_offset; y_offset = row_start_offset;
break; break;
case 90: case 90:
madctl_par |= (MADCTL_MV | MADCTL_MY); madctl_par |= (MADCTL_MV | MADCTL_MY);
x_offset = row1_offset; x_offset = row_start_offset;
y_offset = col1_offset; y_offset = col_start_offset;
break; break;
case 180: case 180:
madctl_par |= (MADCTL_MX | MADCTL_MY); madctl_par |= (MADCTL_MX | MADCTL_MY);
x_offset = col2_offset; x_offset = col_end_offset;
y_offset = row2_offset; y_offset = row_end_offset;
break; break;
case 270: case 270:
madctl_par |= (MADCTL_MV | MADCTL_MX); madctl_par |= (MADCTL_MV | MADCTL_MX);
x_offset = row2_offset; x_offset = row_end_offset;
y_offset = col2_offset; y_offset = col_end_offset;
break; break;
default: default:
return -EINVAL; return -EINVAL;
@ -304,14 +420,23 @@ static struct fbtft_display display = {
.gamma = HSD20_IPS_GAMMA, .gamma = HSD20_IPS_GAMMA,
.fbtftops = { .fbtftops = {
.init_display = init_display, .init_display = init_display,
.write_vmem = write_vmem,
.set_var = set_var, .set_var = set_var,
.set_gamma = set_gamma, .set_gamma = set_gamma,
.blank = blank, .blank = blank,
.set_addr_win = minipitft_set_addr_win,
}, },
}; };
FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7789v", &display); int variant_minipitft13(struct fbtft_display *display)
{
display->fbtftops.set_addr_win = minipitft13_set_addr_win;
return 0;
}
FBTFT_REGISTER_DRIVER_START(&display)
FBTFT_COMPATIBLE("sitronix,st7789v")
FBTFT_VARIANT_COMPATIBLE("fbtft,minipitft13", variant_minipitft13)
FBTFT_REGISTER_DRIVER_END(DRVNAME, &display);
MODULE_ALIAS("spi:" DRVNAME); MODULE_ALIAS("spi:" DRVNAME);
MODULE_ALIAS("platform:" DRVNAME); MODULE_ALIAS("platform:" DRVNAME);

View file

@ -240,7 +240,7 @@ struct fbtft_par {
int fbtft_write_buf_dc(struct fbtft_par *par, void *buf, size_t len, int dc); int fbtft_write_buf_dc(struct fbtft_par *par, void *buf, size_t len, int dc);
__printf(5, 6) __printf(5, 6)
void fbtft_dbg_hex(const struct device *dev, int groupsize, void fbtft_dbg_hex(const struct device *dev, int groupsize,
void *buf, size_t len, const char *fmt, ...); const void *buf, size_t len, const char *fmt, ...);
struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
struct device *dev, struct device *dev,
struct fbtft_platform_data *pdata); struct fbtft_platform_data *pdata);
@ -253,7 +253,7 @@ int fbtft_init_display(struct fbtft_par *par);
int fbtft_probe_common(struct fbtft_display *display, struct spi_device *sdev, int fbtft_probe_common(struct fbtft_display *display, struct spi_device *sdev,
struct platform_device *pdev, struct platform_device *pdev,
const struct of_device_id *dt_ids); const struct of_device_id *dt_ids);
int fbtft_remove_common(struct device *dev, struct fb_info *info); void fbtft_remove_common(struct device *dev, struct fb_info *info);
/* fbtft-io.c */ /* fbtft-io.c */
int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len); int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len);
@ -282,11 +282,11 @@ static int fbtft_driver_probe_spi(struct spi_device *spi) \
return fbtft_probe_common(_display, spi, NULL, dt_ids); \ return fbtft_probe_common(_display, spi, NULL, dt_ids); \
} \ } \
\ \
static int fbtft_driver_remove_spi(struct spi_device *spi) \ static void fbtft_driver_remove_spi(struct spi_device *spi) \
{ \ { \
struct fb_info *info = spi_get_drvdata(spi); \ struct fb_info *info = spi_get_drvdata(spi); \
\ \
return fbtft_remove_common(&spi->dev, info); \ fbtft_remove_common(&spi->dev, info); \
} \ } \
\ \
static int fbtft_driver_probe_pdev(struct platform_device *pdev) \ static int fbtft_driver_probe_pdev(struct platform_device *pdev) \
@ -298,7 +298,8 @@ static int fbtft_driver_remove_pdev(struct platform_device *pdev) \
{ \ { \
struct fb_info *info = platform_get_drvdata(pdev); \ struct fb_info *info = platform_get_drvdata(pdev); \
\ \
return fbtft_remove_common(&pdev->dev, info); \ fbtft_remove_common(&pdev->dev, info); \
return 0; \
} \ } \
\ \
static const struct of_device_id dt_ids[] = { static const struct of_device_id dt_ids[] = {
@ -343,7 +344,10 @@ static int __init fbtft_driver_module_init(void) \
ret = spi_register_driver(&fbtft_driver_spi_driver); \ ret = spi_register_driver(&fbtft_driver_spi_driver); \
if (ret < 0) \ if (ret < 0) \
return ret; \ return ret; \
return platform_driver_register(&fbtft_driver_platform_driver); \ ret = platform_driver_register(&fbtft_driver_platform_driver); \
if (ret < 0) \
spi_unregister_driver(&fbtft_driver_spi_driver); \
return ret; \
} \ } \
\ \
static void __exit fbtft_driver_module_exit(void) \ static void __exit fbtft_driver_module_exit(void) \
@ -355,6 +359,46 @@ static void __exit fbtft_driver_module_exit(void) \
module_init(fbtft_driver_module_init); \ module_init(fbtft_driver_module_init); \
module_exit(fbtft_driver_module_exit); module_exit(fbtft_driver_module_exit);
#define FBTFT_REGISTER_SPI_DRIVER(_name, _comp_vend, _comp_dev, _display) \
\
static const struct of_device_id dt_ids[] = { \
{ .compatible = _comp_vend "," _comp_dev }, \
{}, \
}; \
\
static int fbtft_driver_probe_spi(struct spi_device *spi) \
{ \
return fbtft_probe_common(_display, spi, NULL, dt_ids); \
} \
\
static void fbtft_driver_remove_spi(struct spi_device *spi) \
{ \
struct fb_info *info = spi_get_drvdata(spi); \
\
fbtft_remove_common(&spi->dev, info); \
} \
\
MODULE_DEVICE_TABLE(of, dt_ids); \
\
static const struct spi_device_id spi_ids[] = { \
{ .name = _comp_dev }, \
{}, \
}; \
\
MODULE_DEVICE_TABLE(spi, spi_ids); \
\
static struct spi_driver fbtft_driver_spi_driver = { \
.driver = { \
.name = _name, \
.of_match_table = dt_ids, \
}, \
.id_table = spi_ids, \
.probe = fbtft_driver_probe_spi, \
.remove = fbtft_driver_remove_spi, \
}; \
\
module_spi_driver(fbtft_driver_spi_driver);
#define FBTFT_REGISTER_DRIVER(_name, _compatible, _display) \ #define FBTFT_REGISTER_DRIVER(_name, _compatible, _display) \
FBTFT_REGISTER_DRIVER_START(_display) \ FBTFT_REGISTER_DRIVER_START(_display) \
FBTFT_COMPATIBLE(_compatible) \ FBTFT_COMPATIBLE(_compatible) \

14
st7789_module/reload.sh Normal file
View file

@ -0,0 +1,14 @@
#!/bin/bash
# Unload
sudo dtoverlay -r drm-minipitft114
sudo modprobe -r fb_st7789v
sudo modprobe -r fbtft
# Compile
sudo make
# Load again
sudo modprobe fbtft
sudo insmod ./fb_st7789v.ko
sudo dtoverlay drm-minipitft114