diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c index 6c3b6bfac961d..a1ac963dfe5d0 100644 --- a/drivers/regulator/rpi-panel-attiny-regulator.c +++ b/drivers/regulator/rpi-panel-attiny-regulator.c @@ -143,24 +143,8 @@ static int attiny_lcd_power_disable(struct regulator_dev *rdev) static int attiny_lcd_power_is_enabled(struct regulator_dev *rdev) { struct attiny_lcd *state = rdev_get_drvdata(rdev); - unsigned int data; - int ret, i; - - mutex_lock(&state->lock); - for (i = 0; i < 10; i++) { - ret = regmap_read(rdev->regmap, REG_PORTC, &data); - if (!ret) - break; - usleep_range(10000, 12000); - } - - mutex_unlock(&state->lock); - - if (ret < 0) - return ret; - - return data & PC_RST_BRIDGE_N; + return state->port_states[REG_PORTC - REG_PORTA] & PC_RST_BRIDGE_N; } static const struct regulator_init_data attiny_regulator_default = { @@ -245,39 +229,6 @@ static void attiny_gpio_set(struct gpio_chip *gc, unsigned int off, int val) mutex_unlock(&state->lock); } -static int attiny_i2c_read(struct i2c_client *client, u8 reg, unsigned int *buf) -{ - struct i2c_msg msgs[1]; - u8 addr_buf[1] = { reg }; - u8 data_buf[1] = { 0, }; - int ret; - - /* Write register address */ - msgs[0].addr = client->addr; - msgs[0].flags = 0; - msgs[0].len = ARRAY_SIZE(addr_buf); - msgs[0].buf = addr_buf; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret != ARRAY_SIZE(msgs)) - return -EIO; - - usleep_range(5000, 10000); - - /* Read data from register */ - msgs[0].addr = client->addr; - msgs[0].flags = I2C_M_RD; - msgs[0].len = 1; - msgs[0].buf = data_buf; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret != ARRAY_SIZE(msgs)) - return -EIO; - - *buf = data_buf[0]; - return 0; -} - /* * I2C driver interface functions */ @@ -289,7 +240,6 @@ static int attiny_i2c_probe(struct i2c_client *i2c) struct regulator_dev *rdev; struct attiny_lcd *state; struct regmap *regmap; - unsigned int data; int ret; state = devm_kzalloc(&i2c->dev, sizeof(*state), GFP_KERNEL); @@ -307,22 +257,6 @@ static int attiny_i2c_probe(struct i2c_client *i2c) goto error; } - ret = attiny_i2c_read(i2c, REG_ID, &data); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to read REG_ID reg: %d\n", ret); - goto error; - } - - switch (data) { - case 0xde: /* ver 1 */ - case 0xc3: /* ver 2 */ - break; - default: - dev_err(&i2c->dev, "Unknown Atmel firmware revision: 0x%02x\n", data); - ret = -ENODEV; - goto error; - } - regmap_write(regmap, REG_POWERON, 0); msleep(30); regmap_write(regmap, REG_PWM, 0); @@ -386,6 +320,14 @@ static void attiny_i2c_remove(struct i2c_client *client) mutex_destroy(&state->lock); } +static void attiny_i2c_shutdown(struct i2c_client *client) +{ + struct attiny_lcd *state = i2c_get_clientdata(client); + + regmap_write(state->regmap, REG_PWM, 0); + regmap_write(state->regmap, REG_POWERON, 0); +} + static const struct of_device_id attiny_dt_ids[] = { { .compatible = "raspberrypi,7inch-touchscreen-panel-regulator" }, {}, @@ -400,6 +342,7 @@ static struct i2c_driver attiny_regulator_driver = { }, .probe = attiny_i2c_probe, .remove = attiny_i2c_remove, + .shutdown = attiny_i2c_shutdown, }; module_i2c_driver(attiny_regulator_driver); diff --git a/drivers/video/fbdev/mxc/Kconfig b/drivers/video/fbdev/mxc/Kconfig index d8896a0513d84..329d222494f4d 100644 --- a/drivers/video/fbdev/mxc/Kconfig +++ b/drivers/video/fbdev/mxc/Kconfig @@ -130,3 +130,7 @@ config FB_MXC_DCIC depends on FB_MXC_SYNC_PANEL depends on MXC_IPU_V3 || FB_MXS select VIDEOMODE_HELPERS + +config FB_MXC_RPI_7INCH_LCD + depends on I2C + tristate "Raspberry Pi 7 inch LCD" diff --git a/drivers/video/fbdev/mxc/Makefile b/drivers/video/fbdev/mxc/Makefile index 0cb0925a5282a..6ad13155fa0d0 100644 --- a/drivers/video/fbdev/mxc/Makefile +++ b/drivers/video/fbdev/mxc/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_FB_MXC_RPI_7INCH_LCD) += mxcfb_rpi_7inch.o obj-$(CONFIG_FB_MXC_DISP_FRAMEWORK) += mxc_dispdrv.o obj-$(CONFIG_FB_MXC_MIPI_DSI_NORTHWEST) += mipi_dsi_northwest.o obj-$(CONFIG_FB_MXC_EDID) += mxc_edid.o diff --git a/drivers/video/fbdev/mxc/mipi_dsi.h b/drivers/video/fbdev/mxc/mipi_dsi.h index b8fc12cd60054..9a06cbc91af93 100644 --- a/drivers/video/fbdev/mxc/mipi_dsi.h +++ b/drivers/video/fbdev/mxc/mipi_dsi.h @@ -121,7 +121,9 @@ struct mipi_dsi_info { int dsi_power_on; int lcd_inited; int encoder; - int traffic_mode; + u32 traffic_mode; + u32 non_continuous_clock; + u32 auto_eotp; u32 dphy_pll_config; int dev_id; int disp_id; @@ -187,5 +189,10 @@ void mipid_hx8394_get_lcd_videomode(struct fb_videomode **mode, int *size, struct mipi_lcd_config **data); int mipid_hx8394_lcd_setup(struct mipi_dsi_info *mipi_dsi); #endif +#ifdef CONFIG_FB_MXC_RPI_7INCH_LCD +void mipid_rpi_get_lcd_videomode(struct fb_videomode **mode, int *size, + struct mipi_lcd_config **data); +int mipid_rpi_lcd_setup(struct mipi_dsi_info *mipi_dsi); +#endif #endif diff --git a/drivers/video/fbdev/mxc/mipi_dsi_northwest.c b/drivers/video/fbdev/mxc/mipi_dsi_northwest.c index c33157a860779..12859070b6588 100644 --- a/drivers/video/fbdev/mxc/mipi_dsi_northwest.c +++ b/drivers/video/fbdev/mxc/mipi_dsi_northwest.c @@ -94,6 +94,12 @@ static struct mipi_dsi_match_lcd mipi_dsi_lcd_db[] = { "ROCKTECH-RK055AHD091", {mipid_hx8394_get_lcd_videomode, mipid_hx8394_lcd_setup} }, +#endif +#ifdef CONFIG_FB_MXC_RPI_7INCH_LCD + { + "RPI-7INCH-LCD", + {mipid_rpi_get_lcd_videomode, mipid_rpi_lcd_setup} + }, #endif { "", {NULL, NULL} @@ -375,10 +381,12 @@ static void mipi_dsi_set_mode(struct mipi_dsi_info *mipi_dsi, switch (mode) { case DSI_LP_MODE: - writel(0x1, mipi_dsi->mmio_base + HOST_CFG_NONCONTINUOUS_CLK); + writel(mipi_dsi->non_continuous_clock, + mipi_dsi->mmio_base + HOST_CFG_NONCONTINUOUS_CLK); break; case DSI_HS_MODE: writel(0x0, mipi_dsi->mmio_base + HOST_CFG_NONCONTINUOUS_CLK); + break; default: dev_err(&mipi_dsi->pdev->dev, @@ -449,6 +457,8 @@ static int mipi_dsi_dphy_init(struct mipi_dsi_info *mipi_dsi) "requested data lane num is invalid\n"); return -EINVAL; } + dev_info(&mipi_dsi->pdev->dev, "DSI bit clock: %u bpp %u lanes %u\n", + req_bit_clk, bpp, lcd_config->data_lane_num); if (mipi_dsi->encoder) { if (req_bit_clk > lcd_config->max_phy_clk) @@ -695,13 +705,13 @@ static int mipi_dsi_host_init(struct mipi_dsi_info *mipi_dsi) #endif writel(lane_num, mipi_dsi->mmio_base + HOST_CFG_NUM_LANES); - writel(mipi_dsi->encoder ? 0x0 : 0x1, + writel(mipi_dsi->non_continuous_clock, mipi_dsi->mmio_base + HOST_CFG_NONCONTINUOUS_CLK); writel(0x1, mipi_dsi->mmio_base + HOST_CFG_T_PRE); writel(52, mipi_dsi->mmio_base + HOST_CFG_T_POST); writel(13, mipi_dsi->mmio_base + HOST_CFG_TX_GAP); - writel(mipi_dsi->encoder ? 0x0 : 0x1, - mipi_dsi->mmio_base + HOST_CFG_AUTOINSERT_EOTP); + writel(mipi_dsi->auto_eotp, + mipi_dsi->mmio_base + HOST_CFG_AUTOINSERT_EOTP); writel(0x0, mipi_dsi->mmio_base + HOST_CFG_EXTRA_CMDS_AFTER_EOTP); writel(0x0, mipi_dsi->mmio_base + HOST_CFG_HTX_TO_COUNT); writel(0x0, mipi_dsi->mmio_base + HOST_CFG_LRX_H_TO_COUNT); @@ -717,8 +727,12 @@ static int mipi_dsi_dpi_init(struct mipi_dsi_info *mipi_dsi) uint32_t pixel_fifo_level, hfp_period, hbp_period, hsa_period; struct fb_videomode *mode = mipi_dsi->mode; struct mipi_lcd_config *lcd_config = mipi_dsi->lcd_config; + uint32_t bytes_per_pixel; + uint32_t blank; + uint32_t pl, phl; bpp = fmt_to_bpp(lcd_config->dpi_fmt); + bytes_per_pixel = bpp / 8; writel(mode->xres, mipi_dsi->mmio_base + DPI_PIXEL_PAYLOAD_SIZE); @@ -735,6 +749,28 @@ static int mipi_dsi_dpi_init(struct mipi_dsi_info *mipi_dsi) hbp_period = 0x60; hsa_period = 0xf0; #endif + + /* see drivers/gpu/drm/bridge/nwl-dsi.c */ + pixel_fifo_level = mode->xres; + hfp_period = mode->right_margin * bytes_per_pixel; + hbp_period = mode->left_margin * bytes_per_pixel; + hsa_period = mode->hsync_len * bytes_per_pixel; + /* should be even ?*/ + hfp_period = roundup(hfp_period, 2); + hbp_period = roundup(hbp_period, 2); + hsa_period = roundup(hsa_period, 2); + + blank = hfp_period + hbp_period + hsa_period; + pl = roundup(((hfp_period * 100 / blank) * 32) / 100, 2); + phl = pl; + hfp_period -= pl; + pl = roundup(((hbp_period * 100 / blank) * 32) / 100, 2); + phl += pl; + hbp_period -= pl; + + hsa_period -= (phl <= 32) ? 32 - phl : 0; + dev_dbg(&mipi_dsi->pdev->dev, " Actual hfp/hsa/hbp: %u/%u/%u", + hfp_period, hsa_period, hbp_period); break; case DSI_BURST_MODE: pixel_fifo_level = mode->xres; @@ -779,6 +815,8 @@ static int mipi_dsi_dpi_init(struct mipi_dsi_info *mipi_dsi) writel(0x0, mipi_dsi->mmio_base + DPI_VSYNC_POLARITY); writel(0x0, mipi_dsi->mmio_base + DPI_HSYNC_POLARITY); #endif + dev_info(&mipi_dsi->pdev->dev, "%s: traffic_mode:%u\n", + __func__, mipi_dsi->traffic_mode); writel(mipi_dsi->traffic_mode, mipi_dsi->mmio_base + DPI_VIDEO_MODE); @@ -1068,7 +1106,7 @@ static int mipi_dsi_pkt_write(struct mipi_dsi_info *mipi_dsi, const uint8_t *data = (const uint8_t *)buf; if (len == 0) - /* handle generic long write command */ + /* handle generic short write command */ mipi_dsi_wr_tx_header(mipi_dsi, data_type, data[0], data[1], DSI_LP_MODE, 0); else { reinit_completion(&dsi_tx_done); @@ -1388,6 +1426,12 @@ static int mipi_dsi_probe(struct platform_device *pdev) return -EINVAL; } #endif + /* Properties names should be inverted, but to keep backward + * compatibility no property is treated as previously default value */ + mipi_dsi->non_continuous_clock = !of_property_read_bool(np, + "continuous-clock"); + mipi_dsi->auto_eotp = !of_property_read_bool(np, "no-auto-eotp"); + /* check whether an encoder exists */ endpoint = of_graph_get_next_endpoint(np, NULL); if (endpoint) { @@ -1425,9 +1469,16 @@ static int mipi_dsi_probe(struct platform_device *pdev) } mipi_dsi->encoder = 1; + /* backward compatibility: this settings depended on encoder. + * set option values to match */ + mipi_dsi->non_continuous_clock = 0; + mipi_dsi->auto_eotp = 0; } else { /* Default, using 'BURST-MODE' for mipi panel */ - mipi_dsi->traffic_mode = 2; + ret = of_property_read_u32(np, "dsi-traffic-mode", + &mipi_dsi->traffic_mode); + if (ret < 0 || mipi_dsi->traffic_mode > 2) + mipi_dsi->traffic_mode = DSI_BURST_MODE; ret = of_property_read_string(np, "lcd_panel", &lcd_panel); if (ret) { diff --git a/drivers/video/fbdev/mxc/mxcfb_rpi_7inch.c b/drivers/video/fbdev/mxc/mxcfb_rpi_7inch.c new file mode 100644 index 0000000000000..fdcbf376c5618 --- /dev/null +++ b/drivers/video/fbdev/mxc/mxcfb_rpi_7inch.c @@ -0,0 +1,256 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright(C) 2024-2026 Emcraft Systems + * Author(s): Vladimir Skvortsov + */ +#include +#include +#include +#include +#include +#include +#include +#include