Updated and fixed ST7789v driver
This commit is contained in:
parent
d49b6e9d95
commit
97a7d43e85
7 changed files with 221 additions and 43 deletions
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
fragment@3 {
|
||||
target-path = "/";
|
||||
__overlay__ {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -320,4 +445,4 @@ MODULE_ALIAS("platform:st7789v");
|
|||
|
||||
MODULE_DESCRIPTION("FB driver for the ST7789V LCD Controller");
|
||||
MODULE_AUTHOR("Dennis Menschel");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -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) \
|
||||
|
|
@ -433,4 +477,4 @@ do { \
|
|||
(num) * sizeof(type), format, ##arg); \
|
||||
} while (0)
|
||||
|
||||
#endif /* __LINUX_FBTFT_H */
|
||||
#endif /* __LINUX_FBTFT_H */
|
||||
14
st7789_module/reload.sh
Normal file
14
st7789_module/reload.sh
Normal 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
|
||||
Loading…
Reference in a new issue