diff options
author | Jan-Simon Möller <jsmoeller@linuxfoundation.org> | 2019-06-04 19:25:25 +0200 |
---|---|---|
committer | Jan-Simon Moeller <jsmoeller@linuxfoundation.org> | 2019-06-05 21:53:11 +0000 |
commit | ccb667c35ffdea7a2bc1304750e6b22368cd55f7 (patch) | |
tree | 8d621efea6b6500403898d1e91eed8ecbc4f093d /meta-agl-bsp/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi/dsi/0004-drm-panel-Backport-4.15-support-for-the-Raspberry-Pi.patch | |
parent | a039cce0977ca33e4532de87fd4a1867cc7b21a7 (diff) |
Fix rpi touchscreen support on master
We seem to miss a few bits that changed between kernel 4.9 and kernel 4.14
regarding the 7'' touchscreen.
One addition is the rpi-backlight.dtbo which we also need to use in our create-combined-dtb
recipe for CI use.
We also seem to require https://github.com/raspberrypi/linux/pull/2693#issue-217750943 .
Thanks to Scott Murray for the help digging through this.
v2 and v3: add devicetree changes
v4 and v5: fix name of dtbo
v6: move append to machine include - we need it as a global var
v7: add to config.txt for sdcard boot case
Bug-AGL: SPEC-2465
Change-Id: I2bb3cd974b74a790292e1f36ffdca034928e0bca
Signed-off-by: Jan-Simon Möller <jsmoeller@linuxfoundation.org>
Diffstat (limited to 'meta-agl-bsp/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi/dsi/0004-drm-panel-Backport-4.15-support-for-the-Raspberry-Pi.patch')
-rw-r--r-- | meta-agl-bsp/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi/dsi/0004-drm-panel-Backport-4.15-support-for-the-Raspberry-Pi.patch | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/meta-agl-bsp/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi/dsi/0004-drm-panel-Backport-4.15-support-for-the-Raspberry-Pi.patch b/meta-agl-bsp/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi/dsi/0004-drm-panel-Backport-4.15-support-for-the-Raspberry-Pi.patch new file mode 100644 index 000000000..17c32750b --- /dev/null +++ b/meta-agl-bsp/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi/dsi/0004-drm-panel-Backport-4.15-support-for-the-Raspberry-Pi.patch @@ -0,0 +1,418 @@ +From 7f745c7e13b50911424b9bbb4181d4dc72ef155f Mon Sep 17 00:00:00 2001 +From: Kevin Quigley <kevin@kquigley.co.uk> +Date: Mon, 24 Sep 2018 12:14:41 +0000 +Subject: [PATCH 4/4] drm/panel: Backport 4.15 support for the Raspberry Pi 7" + Touchscreen + +--- + .../drm/panel/panel-raspberrypi-touchscreen.c | 242 ++++++++---------- + 1 file changed, 111 insertions(+), 131 deletions(-) + +diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +index 128523d8d518..2c9c9722734f 100644 +--- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c ++++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +@@ -1,5 +1,5 @@ + /* +- * Copyright © 2016 Broadcom ++ * Copyright © 2016-2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -30,14 +30,15 @@ + */ + + /** +- * DOC: Raspberry Pi 7" touchscreen panel driver. ++ * Raspberry Pi 7" touchscreen panel driver. + * + * The 7" touchscreen consists of a DPI LCD panel, a Toshiba + * TC358762XBG DSI-DPI bridge, and an I2C-connected Atmel ATTINY88-MUR +- * controlling power management, the LCD PWM, and the touchscreen. ++ * controlling power management, the LCD PWM, and initial register ++ * setup of the Tohsiba. + * +- * This driver presents this device as a MIPI DSI panel to the DRM +- * driver, and should expose the touchscreen as a HID device. ++ * This driver controls the TC358762 and ATTINY88, presenting a DSI ++ * device with a drm_panel. + */ + + #include <linux/delay.h> +@@ -58,10 +59,12 @@ + #include <drm/drm_mipi_dsi.h> + #include <drm/drm_panel.h> + ++#define RPI_DSI_DRIVER_NAME "rpi-ts-dsi" ++ + /* I2C registers of the Atmel microcontroller. */ + enum REG_ADDR { + REG_ID = 0x80, +- REG_PORTA, // BIT(2) for horizontal flip, BIT(3) for vertical flip ++ REG_PORTA, /* BIT(2) for horizontal flip, BIT(3) for vertical flip */ + REG_PORTB, + REG_PORTC, + REG_PORTD, +@@ -81,9 +84,6 @@ enum REG_ADDR { + REG_ID2, + }; + +-/* We only turn the PWM on or off, without varying values. */ +-#define RPI_TOUCHSCREEN_MAX_BRIGHTNESS 1 +- + /* DSI D-PHY Layer Registers */ + #define D0W_DPHYCONTTX 0x0004 + #define CLW_DPHYCONTRX 0x0020 +@@ -100,8 +100,6 @@ enum REG_ADDR { + #define PPI_BUSYPPI 0x0108 + #define PPI_LINEINITCNT 0x0110 + #define PPI_LPTXTIMECNT 0x0114 +-//#define PPI_LANEENABLE 0x0134 +-//#define PPI_TX_RX_TA 0x013C + #define PPI_CLS_ATMR 0x0140 + #define PPI_D0S_ATMR 0x0144 + #define PPI_D1S_ATMR 0x0148 +@@ -197,43 +195,23 @@ enum REG_ADDR { + struct rpi_touchscreen { + struct drm_panel base; + struct mipi_dsi_device *dsi; +- struct i2c_client *bridge_i2c; +- +- /* Version of the firmware on the bridge chip */ +- int atmel_ver; ++ struct i2c_client *i2c; + }; + + static const struct drm_display_mode rpi_touchscreen_modes[] = { + { +- /* The DSI PLL can only integer divide from the 2Ghz +- * PLLD, giving us few choices. We pick a divide by 3 +- * as our DSI HS clock, giving us a pixel clock of +- * that divided by 24 bits. Pad out HFP to get our +- * panel to refresh at 60Hz, even if that doesn't +- * match the datasheet. +- */ +-#define PIXEL_CLOCK ((2000000000 / 3) / 24) +-#define VREFRESH 60 +-#define VTOTAL (480 + 7 + 2 + 21) +-#define HACT 800 +-#define HSW 2 +-#define HBP 46 +-#define HFP ((PIXEL_CLOCK / (VTOTAL * VREFRESH)) - (HACT + HSW + HBP)) +- +- /* Round up the pixel clock a bit (10khz), so that the +- * "don't run things faster than the requested clock +- * rate" rule of the clk driver doesn't reject the +- * divide-by-3 mode due to rounding error. ++ /* Modeline comes from the Raspberry Pi firmware, with HFP=1 ++ * plugged in and clock re-computed from that. + */ +- .clock = PIXEL_CLOCK / 1000 + 10, +- .hdisplay = HACT, +- .hsync_start = HACT + HFP, +- .hsync_end = HACT + HFP + HSW, +- .htotal = HACT + HFP + HSW + HBP, ++ .clock = 25979400 / 1000, ++ .hdisplay = 800, ++ .hsync_start = 800 + 1, ++ .hsync_end = 800 + 1 + 2, ++ .htotal = 800 + 1 + 2 + 46, + .vdisplay = 480, + .vsync_start = 480 + 7, + .vsync_end = 480 + 7 + 2, +- .vtotal = VTOTAL, ++ .vtotal = 480 + 7 + 2 + 21, + .vrefresh = 60, + }, + }; +@@ -245,7 +223,7 @@ static struct rpi_touchscreen *panel_to_ts(struct drm_panel *panel) + + static int rpi_touchscreen_i2c_read(struct rpi_touchscreen *ts, u8 reg) + { +- return i2c_smbus_read_byte_data(ts->bridge_i2c, reg); ++ return i2c_smbus_read_byte_data(ts->i2c, reg); + } + + static void rpi_touchscreen_i2c_write(struct rpi_touchscreen *ts, +@@ -253,19 +231,13 @@ static void rpi_touchscreen_i2c_write(struct rpi_touchscreen *ts, + { + int ret; + +- ret = i2c_smbus_write_byte_data(ts->bridge_i2c, reg, val); ++ ret = i2c_smbus_write_byte_data(ts->i2c, reg, val); + if (ret) + dev_err(&ts->dsi->dev, "I2C write failed: %d\n", ret); + } + + static int rpi_touchscreen_write(struct rpi_touchscreen *ts, u16 reg, u32 val) + { +-#if 0 +- /* The firmware uses LP DSI transactions like this to bring up +- * the hardware, which should be faster than using I2C to then +- * pass to the Toshiba. However, I was unable to get it to +- * work. +- */ + u8 msg[] = { + reg, + reg >> 8, +@@ -275,13 +247,7 @@ static int rpi_touchscreen_write(struct rpi_touchscreen *ts, u16 reg, u32 val) + val >> 24, + }; + +- mipi_dsi_dcs_write_buffer(ts->dsi, msg, sizeof(msg)); +-#else +- rpi_touchscreen_i2c_write(ts, REG_WR_ADDRH, reg >> 8); +- rpi_touchscreen_i2c_write(ts, REG_WR_ADDRL, reg); +- rpi_touchscreen_i2c_write(ts, REG_WRITEH, val >> 8); +- rpi_touchscreen_i2c_write(ts, REG_WRITEL, val); +-#endif ++ mipi_dsi_generic_write(ts->dsi, msg, sizeof(msg)); + + return 0; + } +@@ -317,8 +283,7 @@ static int rpi_touchscreen_enable(struct drm_panel *panel) + + rpi_touchscreen_write(ts, DSI_LANEENABLE, + DSI_LANEENABLE_CLOCK | +- DSI_LANEENABLE_D0 | +- (ts->dsi->lanes > 1 ? DSI_LANEENABLE_D1 : 0)); ++ DSI_LANEENABLE_D0); + rpi_touchscreen_write(ts, PPI_D0S_CLRSIPOCOUNT, 0x05); + rpi_touchscreen_write(ts, PPI_D1S_CLRSIPOCOUNT, 0x05); + rpi_touchscreen_write(ts, PPI_D0S_ATMR, 0x00); +@@ -352,6 +317,7 @@ static int rpi_touchscreen_get_modes(struct drm_panel *panel) + struct drm_connector *connector = panel->connector; + struct drm_device *drm = panel->drm; + unsigned int i, num = 0; ++ static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; + + for (i = 0; i < ARRAY_SIZE(rpi_touchscreen_modes); i++) { + const struct drm_display_mode *m = &rpi_touchscreen_modes[i]; +@@ -378,6 +344,8 @@ static int rpi_touchscreen_get_modes(struct drm_panel *panel) + connector->display_info.bpc = 8; + connector->display_info.width_mm = 154; + connector->display_info.height_mm = 86; ++ drm_display_info_set_bus_formats(&connector->display_info, ++ &bus_format, 1); + + return num; + } +@@ -390,51 +358,27 @@ static const struct drm_panel_funcs rpi_touchscreen_funcs = { + .get_modes = rpi_touchscreen_get_modes, + }; + +-static struct i2c_client *rpi_touchscreen_get_i2c(struct device *dev, +- const char *name) +-{ +- struct device_node *node; +- struct i2c_client *client; +- +- node = of_parse_phandle(dev->of_node, name, 0); +- if (!node) +- return ERR_PTR(-ENODEV); +- +- client = of_find_i2c_device_by_node(node); +- +- of_node_put(node); +- +- if (!client) +- return ERR_PTR(-EPROBE_DEFER); +- +- return client; +-} +- +-static int rpi_touchscreen_dsi_probe(struct mipi_dsi_device *dsi) ++static int rpi_touchscreen_probe(struct i2c_client *i2c, ++ const struct i2c_device_id *id) + { +- struct device *dev = &dsi->dev; ++ struct device *dev = &i2c->dev; + struct rpi_touchscreen *ts; ++ struct device_node *endpoint, *dsi_host_node; ++ struct mipi_dsi_host *host; + int ret, ver; ++ struct mipi_dsi_device_info info = { ++ .type = RPI_DSI_DRIVER_NAME, ++ .channel = 0, ++ .node = NULL, ++ }; + + ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; + +- dev_set_drvdata(dev, ts); ++ i2c_set_clientdata(i2c, ts); + +- ts->dsi = dsi; +- dsi->mode_flags = (MIPI_DSI_MODE_VIDEO | +- MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +- MIPI_DSI_MODE_LPM); +- dsi->format = MIPI_DSI_FMT_RGB888; +- dsi->lanes = 1; +- +- ts->bridge_i2c = +- rpi_touchscreen_get_i2c(dev, "raspberrypi,touchscreen-bridge"); +- if (IS_ERR(ts->bridge_i2c)) { +- ret = -EPROBE_DEFER; +- return ret; +- } ++ ts->i2c = i2c; + + ver = rpi_touchscreen_i2c_read(ts, REG_ID); + if (ver < 0) { +@@ -443,11 +387,8 @@ static int rpi_touchscreen_dsi_probe(struct mipi_dsi_device *dsi) + } + + switch (ver) { +- case 0xde: +- ts->atmel_ver = 1; +- break; +- case 0xc3: +- ts->atmel_ver = 2; ++ case 0xde: /* ver 1 */ ++ case 0xc3: /* ver 2 */ + break; + default: + dev_err(dev, "Unknown Atmel firmware revision: 0x%02x\n", ver); +@@ -457,65 +398,104 @@ static int rpi_touchscreen_dsi_probe(struct mipi_dsi_device *dsi) + /* Turn off at boot, so we can cleanly sequence powering on. */ + rpi_touchscreen_i2c_write(ts, REG_POWERON, 0); + +- drm_panel_init(&ts->base); ++ /* Look up the DSI host. It needs to probe before we do. */ ++ endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); ++ dsi_host_node = of_graph_get_remote_port_parent(endpoint); ++ host = of_find_mipi_dsi_host_by_node(dsi_host_node); ++ of_node_put(dsi_host_node); ++ if (!host) { ++ of_node_put(endpoint); ++ return -EPROBE_DEFER; ++ } ++ ++ info.node = of_graph_get_remote_port(endpoint); ++ of_node_put(endpoint); ++ ++ ts->dsi = mipi_dsi_device_register_full(host, &info); ++ if (IS_ERR(ts->dsi)) { ++ dev_err(dev, "DSI device registration failed: %ld\n", ++ PTR_ERR(ts->dsi)); ++ return PTR_ERR(ts->dsi); ++ } ++ + ts->base.dev = dev; + ts->base.funcs = &rpi_touchscreen_funcs; + ++ /* This appears last, as it's what will unblock the DSI host ++ * driver's component bind function. ++ */ + ret = drm_panel_add(&ts->base); +- if (ret < 0) +- goto err_release_bridge; +- +- return mipi_dsi_attach(dsi); ++ if (ret) ++ return ret; + +-err_release_bridge: +- put_device(&ts->bridge_i2c->dev); +- return ret; ++ return 0; + } + +-static int rpi_touchscreen_dsi_remove(struct mipi_dsi_device *dsi) ++static int rpi_touchscreen_remove(struct i2c_client *i2c) + { +- struct device *dev = &dsi->dev; +- struct rpi_touchscreen *ts = dev_get_drvdata(dev); +- int ret; ++ struct rpi_touchscreen *ts = i2c_get_clientdata(i2c); + +- ret = mipi_dsi_detach(dsi); +- if (ret < 0) { +- dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); +- return ret; +- } ++ mipi_dsi_detach(ts->dsi); + +- drm_panel_detach(&ts->base); + drm_panel_remove(&ts->base); + +- put_device(&ts->bridge_i2c->dev); ++ mipi_dsi_device_unregister(ts->dsi); ++ kfree(ts->dsi); + + return 0; + } + +-static void rpi_touchscreen_dsi_shutdown(struct mipi_dsi_device *dsi) ++static int rpi_touchscreen_dsi_probe(struct mipi_dsi_device *dsi) + { +- struct device *dev = &dsi->dev; +- struct rpi_touchscreen *ts = dev_get_drvdata(dev); ++ int ret; + +- rpi_touchscreen_i2c_write(ts, REG_POWERON, 0); ++ dsi->mode_flags = (MIPI_DSI_MODE_VIDEO | ++ MIPI_DSI_MODE_VIDEO_SYNC_PULSE | ++ MIPI_DSI_MODE_LPM); ++ dsi->format = MIPI_DSI_FMT_RGB888; ++ dsi->lanes = 1; ++ ++ ret = mipi_dsi_attach(dsi); ++ ++ if (ret) ++ dev_err(&dsi->dev, "failed to attach dsi to host: %d\n", ret); ++ ++ return ret; + } + +-static const struct of_device_id rpi_touchscreen_of_match[] = { +- { .compatible = "raspberrypi,touchscreen" }, ++static struct mipi_dsi_driver rpi_touchscreen_dsi_driver = { ++ .driver.name = RPI_DSI_DRIVER_NAME, ++ .probe = rpi_touchscreen_dsi_probe, ++}; ++ ++static const struct of_device_id rpi_touchscreen_of_ids[] = { ++ { .compatible = "raspberrypi,7inch-touchscreen-panel" }, + { } /* sentinel */ + }; +-MODULE_DEVICE_TABLE(of, rpi_touchscreen_of_match); ++MODULE_DEVICE_TABLE(of, rpi_touchscreen_of_ids); + +-static struct mipi_dsi_driver rpi_touchscreen_driver = { ++static struct i2c_driver rpi_touchscreen_driver = { + .driver = { +- .name = "raspberrypi-touchscreen", +- .of_match_table = rpi_touchscreen_of_match, ++ .name = "rpi_touchscreen", ++ .of_match_table = rpi_touchscreen_of_ids, + }, +- .probe = rpi_touchscreen_dsi_probe, +- .remove = rpi_touchscreen_dsi_remove, +- .shutdown = rpi_touchscreen_dsi_shutdown, ++ .probe = rpi_touchscreen_probe, ++ .remove = rpi_touchscreen_remove, + }; +-module_mipi_dsi_driver(rpi_touchscreen_driver); ++ ++static int __init rpi_touchscreen_init(void) ++{ ++ mipi_dsi_driver_register(&rpi_touchscreen_dsi_driver); ++ return i2c_add_driver(&rpi_touchscreen_driver); ++} ++module_init(rpi_touchscreen_init); ++ ++static void __exit rpi_touchscreen_exit(void) ++{ ++ i2c_del_driver(&rpi_touchscreen_driver); ++ mipi_dsi_driver_unregister(&rpi_touchscreen_dsi_driver); ++} ++module_exit(rpi_touchscreen_exit); + + MODULE_AUTHOR("Eric Anholt <eric@anholt.net>"); + MODULE_DESCRIPTION("Raspberry Pi 7-inch touchscreen driver"); +-- +2.21.0 + |