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
if not config['kernel_upgrade']:
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
@ -309,11 +304,10 @@ def install_drivers():
shell.pushd("st7789_module")
if not shell.run_command("make"):
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 {module}.ko /lib/modules/{shell.release()}/kernel/drivers/staging/fbtft/{module}.ko")
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"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()
# We may need to unzip the /lib/modules/6.1.19-v8+/kernel/drivers/staging/fbtft/fb_st7789v.ko.xz file
return True
def update_configtxt(rotation_override=None):
@ -759,4 +753,5 @@ restart the script and choose a different orientation.""".format(rotation=pitftr
# Main function
if __name__ == "__main__":
shell.require_root()
shell.check_kernel_userspace_mismatch()
main()

View file

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

View file

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

View file

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

View file

@ -7,9 +7,13 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/module.h>
#include <video/mipi_display.h>
#include "fbtft.h"
@ -66,13 +70,68 @@ enum st7789v_command {
#define MADCTL_MX BIT(6) /* bitmask for column address order */
#define MADCTL_MY BIT(7) /* bitmask for page address order */
static u32 col1_offset = 0;
static u32 col2_offset = 0;
static u32 row1_offset = 0;
static u32 row2_offset = 0;
/* 60Hz for 16.6ms, configured as 2*16.6ms */
#define PANEL_TE_TIMEOUT_MS 33
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 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
*
@ -89,6 +148,14 @@ static short y_offset = 0;
*/
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 */
write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE);
mdelay(120);
@ -144,6 +211,10 @@ static int init_display(struct fbtft_par *par)
*/
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);
if (HSD20_IPS)
@ -152,7 +223,51 @@ static int init_display(struct fbtft_par *par)
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)
{
xs += x_offset;
@ -185,35 +300,36 @@ static int set_var(struct fbtft_par *par)
madctl_par |= MADCTL_BGR;
if (width < 240) {
// Display is centered
row1_offset = row2_offset = (int)((320 - height + 1) / 2);
col1_offset = (int)((240 - width) / 2);
col2_offset = (int)((240 - width + 1) / 2);
// Smaller displays are centered
row_start_offset = row_end_offset = (int)((320 - height + 1) / 2);
col_start_offset = (int)((240 - width) / 2);
col_end_offset = (int)((240 - width + 1) / 2); // Account for extra pixel
} else {
row1_offset = 0;
row2_offset = (320 - height);
col1_offset = col2_offset = (240 - width);
// Larger displays are left-aligned
row_start_offset = 0;
row_end_offset = (320 - height);
col_start_offset = col_end_offset = 0;
}
switch (par->info->var.rotate) {
case 0:
x_offset = col1_offset;
y_offset = row1_offset;
x_offset = col_start_offset;
y_offset = row_start_offset;
break;
case 90:
madctl_par |= (MADCTL_MV | MADCTL_MY);
x_offset = row1_offset;
y_offset = col1_offset;
x_offset = row_start_offset;
y_offset = col_start_offset;
break;
case 180:
madctl_par |= (MADCTL_MX | MADCTL_MY);
x_offset = col2_offset;
y_offset = row2_offset;
x_offset = col_end_offset;
y_offset = row_end_offset;
break;
case 270:
madctl_par |= (MADCTL_MV | MADCTL_MX);
x_offset = row2_offset;
y_offset = col2_offset;
x_offset = row_end_offset;
y_offset = col_end_offset;
break;
default:
return -EINVAL;
@ -304,14 +420,23 @@ static struct fbtft_display display = {
.gamma = HSD20_IPS_GAMMA,
.fbtftops = {
.init_display = init_display,
.write_vmem = write_vmem,
.set_var = set_var,
.set_gamma = set_gamma,
.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("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);
__printf(5, 6)
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 device *dev,
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,
struct platform_device *pdev,
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 */
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); \
} \
\
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); \
\
return fbtft_remove_common(&spi->dev, info); \
fbtft_remove_common(&spi->dev, info); \
} \
\
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); \
\
return fbtft_remove_common(&pdev->dev, info); \
fbtft_remove_common(&pdev->dev, info); \
return 0; \
} \
\
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); \
if (ret < 0) \
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) \
@ -355,6 +359,46 @@ static void __exit fbtft_driver_module_exit(void) \
module_init(fbtft_driver_module_init); \
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) \
FBTFT_REGISTER_DRIVER_START(_display) \
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