diff options
| author | Dave Airlie <airlied@redhat.com> | 2026-05-08 14:14:24 +1000 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2026-05-08 14:16:04 +1000 |
| commit | f96538285cfdbb3acf5e3356e0bb88c38815790b (patch) | |
| tree | c3042402dac03417cb32cca85ad67f56de7e50cd /drivers/gpu | |
| parent | bc0400e6f41cbc43a5eaa5ed1c7749da7af7eb1d (diff) | |
| parent | 921578cf373981eba92774a27f7644a11282cf89 (diff) | |
Merge tag 'drm-misc-next-2026-05-07' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next
drm-misc-next for v7.2-rc1:
UAPI Changes:
- Support medium/low power modes in amdxdna.
- Support limiting frequency in ivpu.
- Document license for drm core uAPI headers.
- Add the following DRM formats: P230, Y7, XYYY2101010, T430,
XVUY210101010.
Cross-subsystem Changes:
- Add and improve dt-bindings.
- Remove unused dma-fence-array's signal_on_any support.
Core Changes:
- Do not call drop_master on file close if not master.
- Convert drm-bridge and drm/atomic to use drm_printf_indent.
- Remove the extra call to drm_connector_attach_encoder after
drm_bridge_connector_init().
- Assorted docbook updates.
Driver Changes:
- Bugfixes in amdxdna, ivpu, mipi-dsi, imagination, nouveau, panthor,
bridge/analogix_dp, ipv3, lontium-lt8912b, verisilicon, tve200,
etnaviv, panel/focaltech-ota7290b, panel/jadard-jd9365da-h3,
bridge/ite-it6263, renesas, xlnx, bridge/cdns-dsi, gma500,
bridge/microchip-lvds, mgag200.
- Add support for MStar TSUMU88ADT3-LF-1 bridge.
- Add support for WaveShare 7, Novatek NT35532, Startek KD070HDFLD092,
ChipWealth CH13726A AMOLED, Team Source Display TST070WSNE-196C,
Displaytech DT050BTFT-PTS panels.
- Improve mipi-dsi shutdown and convert a panasonic panel to use the
mipi-dsi wrappers.
- Allowing dumping vbios over debugfs in GSP-RM mode.
- Update maintainers for ivpu, add reviewer for drm-bridge code
and update maintainers for LT8912B DRM HDMI bridge.
- Add test pattern support to bridge/ti-sn65dsi83.
- Convert vmwgfx to vblank timers.
- Add power management to sysfb drm drivers to allow suspend/resume.
- Support the aforementioned new drm formats in xlnx/qynqmp.
- Fix panel Kconfig dependencies.
- Add carveout support for debugging and bringup to amxdna.
- Add support for long command tx via videobuffer in bridge/tc358768.
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patch.msgid.link/f73f342d-6efb-416d-81b0-1716bdd98d5f@linux.intel.com
Diffstat (limited to 'drivers/gpu')
115 files changed, 2815 insertions, 897 deletions
diff --git a/drivers/gpu/drm/adp/adp_drv.c b/drivers/gpu/drm/adp/adp_drv.c index a5913c71b39c..ce9dd6222634 100644 --- a/drivers/gpu/drm/adp/adp_drv.c +++ b/drivers/gpu/drm/adp/adp_drv.c @@ -444,8 +444,6 @@ static int adp_setup_mode_config(struct adp_drv_private *adp) if (IS_ERR(adp->connector)) return PTR_ERR(adp->connector); - drm_connector_attach_encoder(adp->connector, adp->encoder); - ret = drm_vblank_init(drm, drm->mode_config.num_crtc); if (ret < 0) { drm_err(drm, "failed to initialize vblank"); diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index b47d8eea4566..821a3008a1e7 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -768,8 +768,6 @@ static int adv7511_connector_init(struct adv7511 *adv) return PTR_ERR(connector); } - drm_connector_attach_encoder(connector, bridge->encoder); - return 0; } diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 6bfb43b07604..8cf6b73bceac 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1486,7 +1486,7 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev) dp->plat_data->next_bridge = devm_drm_panel_bridge_add(dp->dev, dp->plat_data->panel); if (IS_ERR(dp->plat_data->next_bridge)) { - ret = PTR_ERR(bridge); + ret = PTR_ERR(dp->plat_data->next_bridge); goto err_unregister_aux; } } diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c index 50ea40a6ae05..cf90d4468b5c 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c @@ -1230,7 +1230,7 @@ static const struct mipi_dsi_host_ops cdns_dsi_ops = { .transfer = cdns_dsi_transfer, }; -static int __maybe_unused cdns_dsi_resume(struct device *dev) +static int cdns_dsi_resume(struct device *dev) { struct cdns_dsi *dsi = dev_get_drvdata(dev); @@ -1241,7 +1241,7 @@ static int __maybe_unused cdns_dsi_resume(struct device *dev) return 0; } -static int __maybe_unused cdns_dsi_suspend(struct device *dev) +static int cdns_dsi_suspend(struct device *dev) { struct cdns_dsi *dsi = dev_get_drvdata(dev); @@ -1251,8 +1251,9 @@ static int __maybe_unused cdns_dsi_suspend(struct device *dev) return 0; } -static UNIVERSAL_DEV_PM_OPS(cdns_dsi_pm_ops, cdns_dsi_suspend, cdns_dsi_resume, - NULL); +static const struct dev_pm_ops cdns_dsi_pm_ops = { + RUNTIME_PM_OPS(cdns_dsi_suspend, cdns_dsi_resume, NULL) +}; static int cdns_dsi_drm_probe(struct platform_device *pdev) { @@ -1399,7 +1400,7 @@ static struct platform_driver cdns_dsi_platform_driver = { .driver = { .name = "cdns-dsi", .of_match_table = cdns_dsi_of_match, - .pm = &cdns_dsi_pm_ops, + .pm = pm_ptr(&cdns_dsi_pm_ops), }, }; module_platform_driver(cdns_dsi_platform_driver); diff --git a/drivers/gpu/drm/bridge/ite-it6263.c b/drivers/gpu/drm/bridge/ite-it6263.c index 48499aaba6a9..c7d588be12cb 100644 --- a/drivers/gpu/drm/bridge/ite-it6263.c +++ b/drivers/gpu/drm/bridge/ite-it6263.c @@ -200,6 +200,7 @@ struct it6263 { struct regmap *lvds_regmap; struct drm_bridge bridge; struct drm_bridge *next_bridge; + struct gpio_desc *reset_gpio; int lvds_data_mapping; bool lvds_dual_link; bool lvds_link12_swap; @@ -603,6 +604,15 @@ static void it6263_bridge_atomic_enable(struct drm_bridge *bridge, bool pclk_high; int i, ret; + it6263_hw_reset(it->reset_gpio); + + ret = it6263_lvds_set_i2c_addr(it); + if (ret) + dev_err(it->dev, "failed to set I2C addr\n"); + + it6263_lvds_config(it); + it6263_hdmi_config(it); + connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); crtc = drm_atomic_get_new_connector_state(state, connector)->crtc; @@ -697,8 +707,6 @@ static int it6263_bridge_attach(struct drm_bridge *bridge, return ret; } - drm_connector_attach_encoder(connector, encoder); - return 0; } @@ -815,7 +823,6 @@ static int it6263_hdmi_write_hdmi_infoframe(struct drm_bridge *bridge, regmap_write(regmap, HDMI_REG_PKT_NULL_CTRL, ENABLE_PKT | REPEAT_PKT); - return 0; } @@ -840,7 +847,6 @@ static const struct drm_bridge_funcs it6263_bridge_funcs = { static int it6263_probe(struct i2c_client *client) { struct device *dev = &client->dev; - struct gpio_desc *reset_gpio; struct it6263 *it; int ret; @@ -858,9 +864,9 @@ static int it6263_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(it->hdmi_regmap), "failed to init I2C regmap for HDMI\n"); - reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(reset_gpio)) - return dev_err_probe(dev, PTR_ERR(reset_gpio), + it->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(it->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(it->reset_gpio), "failed to get reset gpio\n"); ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(it6263_supplies), @@ -872,12 +878,6 @@ static int it6263_probe(struct i2c_client *client) if (ret) return ret; - it6263_hw_reset(reset_gpio); - - ret = it6263_lvds_set_i2c_addr(it); - if (ret) - return dev_err_probe(dev, ret, "failed to set I2C addr\n"); - it->lvds_i2c = devm_i2c_new_dummy_device(dev, client->adapter, LVDS_INPUT_CTRL_I2C_ADDR); if (IS_ERR(it->lvds_i2c)) @@ -890,9 +890,6 @@ static int it6263_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(it->lvds_regmap), "failed to init I2C regmap for LVDS\n"); - it6263_lvds_config(it); - it6263_hdmi_config(it); - i2c_set_clientdata(client, it); it->bridge.of_node = dev->of_node; diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 0651e44fc07e..6b7cb132a437 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -2048,7 +2048,7 @@ static void it6505_start_hdcp(struct it6505 *it6505) DRM_DEV_DEBUG_DRIVER(dev, "start"); it6505_reset_hdcp(it6505); - queue_delayed_work(system_wq, &it6505->hdcp_work, + queue_delayed_work(system_percpu_wq, &it6505->hdcp_work, msecs_to_jiffies(2400)); } diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index 8a0b48efca58..729b12b67470 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -493,6 +493,7 @@ static int lt8912_attach_dsi(struct lt8912 *lt) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM | + MIPI_DSI_MODE_VIDEO_NO_HFP | MIPI_DSI_MODE_NO_EOT_PACKET; ret = devm_mipi_dsi_attach(dev, dsi); diff --git a/drivers/gpu/drm/bridge/microchip-lvds.c b/drivers/gpu/drm/bridge/microchip-lvds.c index 9f4ff82bc6b4..12fc442f9867 100644 --- a/drivers/gpu/drm/bridge/microchip-lvds.c +++ b/drivers/gpu/drm/bridge/microchip-lvds.c @@ -11,6 +11,7 @@ #include <linux/component.h> #include <linux/delay.h> #include <linux/jiffies.h> +#include <linux/media-bus-format.h> #include <linux/mfd/syscon.h> #include <linux/of_graph.h> #include <linux/pinctrl/devinfo.h> @@ -23,7 +24,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_of.h> -#include <drm/drm_panel.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> @@ -41,9 +41,11 @@ /* Bitfields in LVDSC_CFGR (Configuration Register) */ #define LVDSC_CFGR_PIXSIZE_24BITS 0 +#define LVDSC_CFGR_PIXSIZE_18BITS BIT(0) #define LVDSC_CFGR_DEN_POL_HIGH 0 #define LVDSC_CFGR_DC_UNBALANCED 0 #define LVDSC_CFGR_MAPPING_JEIDA BIT(6) +#define LVDSC_CFGR_MAPPING_VESA 0 /*Bitfields in LVDSC_SR */ #define LVDSC_SR_CS BIT(0) @@ -56,7 +58,6 @@ struct mchp_lvds { struct device *dev; void __iomem *regs; struct clk *pclk; - struct drm_panel *panel; struct drm_bridge bridge; struct drm_bridge *panel_bridge; }; @@ -76,9 +77,10 @@ static inline void lvds_writel(struct mchp_lvds *lvds, u32 offset, u32 val) writel_relaxed(val, lvds->regs + offset); } -static void lvds_serialiser_on(struct mchp_lvds *lvds) +static void lvds_serialiser_on(struct mchp_lvds *lvds, u32 bus_format) { unsigned long timeout = jiffies + msecs_to_jiffies(LVDS_POLL_TIMEOUT_MS); + u8 map, pix_size; /* The LVDSC registers can only be written if WPEN is cleared */ lvds_writel(lvds, LVDSC_WPMR, (LVDSC_WPMR_WPKEY_PSSWD & @@ -93,11 +95,24 @@ static void lvds_serialiser_on(struct mchp_lvds *lvds) usleep_range(1000, 2000); } + switch (bus_format) { + case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: + map = LVDSC_CFGR_MAPPING_JEIDA; + pix_size = LVDSC_CFGR_PIXSIZE_18BITS; + break; + case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: + map = LVDSC_CFGR_MAPPING_VESA; + pix_size = LVDSC_CFGR_PIXSIZE_24BITS; + break; + default: + map = LVDSC_CFGR_MAPPING_JEIDA; + pix_size = LVDSC_CFGR_PIXSIZE_24BITS; + break; + } + /* Configure the LVDSC */ - lvds_writel(lvds, LVDSC_CFGR, (LVDSC_CFGR_MAPPING_JEIDA | - LVDSC_CFGR_DC_UNBALANCED | - LVDSC_CFGR_DEN_POL_HIGH | - LVDSC_CFGR_PIXSIZE_24BITS)); + lvds_writel(lvds, LVDSC_CFGR, map | LVDSC_CFGR_DC_UNBALANCED | + LVDSC_CFGR_DEN_POL_HIGH | pix_size); /* Enable the LVDS serializer */ lvds_writel(lvds, LVDSC_CR, LVDSC_CR_SER_EN); @@ -113,9 +128,11 @@ static int mchp_lvds_attach(struct drm_bridge *bridge, bridge, flags); } -static void mchp_lvds_enable(struct drm_bridge *bridge) +static void mchp_lvds_atomic_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { struct mchp_lvds *lvds = bridge_to_lvds(bridge); + struct drm_connector *connector; int ret; ret = clk_prepare_enable(lvds->pclk); @@ -130,10 +147,18 @@ static void mchp_lvds_enable(struct drm_bridge *bridge) return; } - lvds_serialiser_on(lvds); + /* default to jeida-24 */ + u32 bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA; + + connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); + if (connector && connector->display_info.num_bus_formats) + bus_format = connector->display_info.bus_formats[0]; + + lvds_serialiser_on(lvds, bus_format); } -static void mchp_lvds_disable(struct drm_bridge *bridge) +static void mchp_lvds_atomic_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { struct mchp_lvds *lvds = bridge_to_lvds(bridge); @@ -143,15 +168,14 @@ static void mchp_lvds_disable(struct drm_bridge *bridge) static const struct drm_bridge_funcs mchp_lvds_bridge_funcs = { .attach = mchp_lvds_attach, - .enable = mchp_lvds_enable, - .disable = mchp_lvds_disable, + .atomic_enable = mchp_lvds_atomic_enable, + .atomic_disable = mchp_lvds_atomic_disable, }; static int mchp_lvds_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mchp_lvds *lvds; - struct device_node *port; int ret; if (!dev->of_node) @@ -173,19 +197,6 @@ static int mchp_lvds_probe(struct platform_device *pdev) return dev_err_probe(lvds->dev, PTR_ERR(lvds->pclk), "could not get pclk_lvds\n"); - port = of_graph_get_remote_node(dev->of_node, 1, 0); - if (!port) { - dev_err(dev, - "can't find port point, please init lvds panel port!\n"); - return -ENODEV; - } - - lvds->panel = of_drm_find_panel(port); - of_node_put(port); - - if (IS_ERR(lvds->panel)) - return -EPROBE_DEFER; - lvds->panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0); if (IS_ERR(lvds->panel_bridge)) diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c index 8aa31ca3c72d..cc13c98f9be6 100644 --- a/drivers/gpu/drm/bridge/simple-bridge.c +++ b/drivers/gpu/drm/bridge/simple-bridge.c @@ -271,6 +271,11 @@ static const struct of_device_id simple_bridge_match[] = { .connector_type = DRM_MODE_CONNECTOR_HDMIA, }, }, { + .compatible = "mstar,tsumu88adt3-lf-1", + .data = &(const struct simple_bridge_info) { + .connector_type = DRM_MODE_CONNECTOR_HDMIA, + }, + }, { .compatible = "parade,ps185hdm", .data = &(const struct simple_bridge_info) { .connector_type = DRM_MODE_CONNECTOR_HDMIA, diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c index e652a2bcd64a..0f2820b37302 100644 --- a/drivers/gpu/drm/bridge/tc358768.c +++ b/drivers/gpu/drm/bridge/tc358768.c @@ -45,6 +45,9 @@ /* Debug (16-bit addressable) */ #define TC358768_VBUFCTRL 0x00E0 +#define TC358768_VBUFCTRL_VBUF_EN BIT(15) +#define TC358768_VBUFCTRL_TX_EN BIT(14) +#define TC358768_VBUFCTRL_MASK BIT(13) #define TC358768_DBG_WIDTH 0x00E2 #define TC358768_DBG_VBLANK 0x00E4 #define TC358768_DBG_DATA 0x00E8 @@ -115,7 +118,7 @@ #define TC358768_DSI_HACT 0x062C /* TC358768_DSI_CONTROL (0x040C) register */ -#define TC358768_DSI_CONTROL_DIS_MODE BIT(15) +#define TC358768_DSI_CONTROL_DSI_MODE BIT(15) #define TC358768_DSI_CONTROL_TXMD BIT(7) #define TC358768_DSI_CONTROL_HSCKMD BIT(5) #define TC358768_DSI_CONTROL_EOTDIS BIT(0) @@ -123,7 +126,7 @@ /* TC358768_DSI_CONFW (0x0500) register */ #define TC358768_DSI_CONFW_MODE_SET (5 << 29) #define TC358768_DSI_CONFW_MODE_CLR (6 << 29) -#define TC358768_DSI_CONFW_ADDR_DSI_CONTROL (0x3 << 24) +#define TC358768_DSI_CONFW_ADDR(x) ((x) << 24) /* TC358768_DSICMD_TX (0x0600) register */ #define TC358768_DSI_CMDTX_DC_START BIT(0) @@ -232,6 +235,36 @@ static void tc358768_update_bits(struct tc358768_priv *priv, u32 reg, u32 mask, tc358768_write(priv, reg, tmp); } +static void tc358768_confw_update_bits(struct tc358768_priv *priv, u16 reg, + u16 mask, u16 val) +{ + u8 confw_addr; + u32 confw_val; + + switch (reg) { + case TC358768_DSI_CONTROL: + confw_addr = 0x3; + break; + default: + priv->error = -EINVAL; + return; + } + + if (mask != val) { + confw_val = TC358768_DSI_CONFW_MODE_CLR | + TC358768_DSI_CONFW_ADDR(confw_addr) | + mask; + tc358768_write(priv, TC358768_DSI_CONFW, confw_val); + } + + if (val & mask) { + confw_val = TC358768_DSI_CONFW_MODE_SET | + TC358768_DSI_CONFW_ADDR(confw_addr) | + (val & mask); + tc358768_write(priv, TC358768_DSI_CONFW, confw_val); + } +} + static void tc358768_dsicmd_tx(struct tc358768_priv *priv) { u32 val; @@ -448,6 +481,8 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host, DRM_MODE_CONNECTOR_DSI); if (IS_ERR(bridge)) return PTR_ERR(bridge); + + bridge->pre_enable_prev_first = true; } priv->output.dev = dev; @@ -505,9 +540,21 @@ static ssize_t tc358768_dsi_host_transfer(struct mipi_dsi_host *host, return -ENOTSUPP; } + if (msg->tx_len > 1024) { + dev_warn(priv->dev, "Maximum 1024 byte MIPI tx is supported\n"); + return -EINVAL; + } + if (msg->tx_len > 8) { - dev_warn(priv->dev, "Maximum 8 byte MIPI tx is supported\n"); - return -ENOTSUPP; + u32 confctl; + + tc358768_read(priv, TC358768_CONFCTL, &confctl); + + if (confctl & BIT(6)) { + dev_warn(priv->dev, + "Video is currently active. Unable to transmit long command\n"); + return -EBUSY; + } } ret = mipi_dsi_create_packet(&packet, msg); @@ -520,23 +567,66 @@ static ssize_t tc358768_dsi_host_transfer(struct mipi_dsi_host *host, tc358768_write(priv, TC358768_DSICMD_WC, 0); tc358768_write(priv, TC358768_DSICMD_WD0, (packet.header[2] << 8) | packet.header[1]); - } else { - int i; - + tc358768_dsicmd_tx(priv); + } else if (packet.payload_length <= 8) { tc358768_write(priv, TC358768_DSICMD_TYPE, (0x40 << 8) | (packet.header[0] & 0x3f)); tc358768_write(priv, TC358768_DSICMD_WC, packet.payload_length); - for (i = 0; i < packet.payload_length; i += 2) { + + for (int i = 0; i < packet.payload_length; i += 2) { u16 val = packet.payload[i]; if (i + 1 < packet.payload_length) val |= packet.payload[i + 1] << 8; - tc358768_write(priv, TC358768_DSICMD_WD0 + i, val); } - } - tc358768_dsicmd_tx(priv); + tc358768_dsicmd_tx(priv); + } else { + unsigned long tx_sleep_us; + size_t len; + + /* For packets over 8 bytes we need to use the video buffer */ + tc358768_write(priv, TC358768_DATAFMT, BIT(0)); /* txdt_en */ + tc358768_write(priv, TC358768_DSITX_DT, packet.header[0] & 0x3f); + tc358768_write(priv, TC358768_CMDBYTE, packet.payload_length); + tc358768_write(priv, TC358768_VBUFCTRL, TC358768_VBUFCTRL_VBUF_EN); + + /* + * Write the payload in 2-byte chunks, and pad with zeroes to + * align to 4 bytes. + */ + len = ALIGN(packet.payload_length, 4); + + for (int i = 0; i < len; i += 2) { + u16 val = 0; + + if (i < packet.payload_length) + val |= packet.payload[i]; + if (i + 1 < packet.payload_length) + val |= packet.payload[i + 1] << 8; + + tc358768_write(priv, TC358768_DBG_DATA, val); + } + + /* Start transmission */ + tc358768_write(priv, TC358768_VBUFCTRL, + TC358768_VBUFCTRL_VBUF_EN | + TC358768_VBUFCTRL_TX_EN | + TC358768_VBUFCTRL_MASK); + + /* + * The TC358768 spec says to wait until the transmission has + * been finished, estimating the sleep time based on the payload + * and clock rates. We use a simple safe estimate of 2us per + * byte (LP mode transmission). + */ + tx_sleep_us = packet.payload_length * 2; + usleep_range(tx_sleep_us, tx_sleep_us * 2); + + tc358768_write(priv, TC358768_VBUFCTRL, TC358768_VBUFCTRL_MASK); + tc358768_write(priv, TC358768_VBUFCTRL, 0); /* Stop transmission */ + } ret = tc358768_clear_error(priv); if (ret) @@ -690,8 +780,7 @@ static void tc358768_bridge_atomic_pre_enable(struct drm_bridge *bridge, { struct tc358768_priv *priv = bridge_to_tc358768(bridge); struct mipi_dsi_device *dsi_dev = priv->output.dev; - unsigned long mode_flags = dsi_dev->mode_flags; - u32 val, val2, lptxcnt, hact, data_type; + u32 val, mask, val2, lptxcnt, hact; s32 raw_val; struct drm_crtc_state *crtc_state; struct drm_connector_state *conn_state; @@ -712,11 +801,6 @@ static void tc358768_bridge_atomic_pre_enable(struct drm_bridge *bridge, u32 dsi_vsdly; const u32 internal_dly = 40; - if (mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) { - dev_warn_once(dev, "Non-continuous mode unimplemented, falling back to continuous\n"); - mode_flags &= ~MIPI_DSI_CLOCK_NON_CONTINUOUS; - } - tc358768_hw_enable(priv); ret = tc358768_sw_reset(priv); @@ -726,6 +810,9 @@ static void tc358768_bridge_atomic_pre_enable(struct drm_bridge *bridge, return; } + /* Release RstPtr so that the video buffer can be used for DSI commands */ + tc358768_update_bits(priv, TC358768_PP_MISC, BIT(14), 0); + connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); conn_state = drm_atomic_get_new_connector_state(state, connector); crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); @@ -742,30 +829,20 @@ static void tc358768_bridge_atomic_pre_enable(struct drm_bridge *bridge, dsiclk = priv->dsiclk; hsbyteclk = dsiclk / 4; - /* Data Format Control Register */ - val = BIT(2) | BIT(1) | BIT(0); /* rdswap_en | dsitx_en | txdt_en */ switch (dsi_dev->format) { case MIPI_DSI_FMT_RGB888: - val |= (0x3 << 4); hact = vm.hactive * 3; - data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; break; case MIPI_DSI_FMT_RGB666: - val |= (0x4 << 4); hact = vm.hactive * 3; - data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18; break; case MIPI_DSI_FMT_RGB666_PACKED: - val |= (0x4 << 4) | BIT(3); hact = vm.hactive * 18 / 8; - data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18; break; case MIPI_DSI_FMT_RGB565: - val |= (0x5 << 4); hact = vm.hactive * 2; - data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; break; default: dev_err(dev, "Invalid data format (%u)\n", @@ -921,9 +998,6 @@ static void tc358768_bridge_atomic_pre_enable(struct drm_bridge *bridge, /* VSDly[9:0] */ tc358768_write(priv, TC358768_VSDLY, dsi_vsdly - internal_dly); - tc358768_write(priv, TC358768_DATAFMT, val); - tc358768_write(priv, TC358768_DSITX_DT, data_type); - /* Enable D-PHY (HiZ->LP11) */ tc358768_write(priv, TC358768_CLW_CNTRL, 0x0000); /* Enable lanes */ @@ -1000,7 +1074,7 @@ static void tc358768_bridge_atomic_pre_enable(struct drm_bridge *bridge, tc358768_write(priv, TC358768_HSTXVREGEN, val); tc358768_write(priv, TC358768_TXOPTIONCNTRL, - (mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ? 0 : BIT(0)); + (dsi_dev->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ? 0 : BIT(0)); /* TXTAGOCNT[26:16] RXTASURECNT[10:0] */ val = tc358768_ps_to_ns((lptxcnt + 1) * hsbyteclk_ps * 4); @@ -1063,33 +1137,63 @@ static void tc358768_bridge_atomic_pre_enable(struct drm_bridge *bridge, tc358768_write(priv, TC358768_DSI_START, 0x1); /* Configure DSI_Control register */ - val = TC358768_DSI_CONFW_MODE_CLR | TC358768_DSI_CONFW_ADDR_DSI_CONTROL; - val |= TC358768_DSI_CONTROL_TXMD | TC358768_DSI_CONTROL_HSCKMD | - 0x3 << 1 | TC358768_DSI_CONTROL_EOTDIS; - tc358768_write(priv, TC358768_DSI_CONFW, val); + val = (dsi_dev->lanes - 1) << 1; - val = TC358768_DSI_CONFW_MODE_SET | TC358768_DSI_CONFW_ADDR_DSI_CONTROL; - val |= (dsi_dev->lanes - 1) << 1; + if (!(dsi_dev->mode_flags & MIPI_DSI_MODE_LPM)) + val |= TC358768_DSI_CONTROL_TXMD; - val |= TC358768_DSI_CONTROL_TXMD; - - if (!(mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)) + if (!(dsi_dev->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)) val |= TC358768_DSI_CONTROL_HSCKMD; if (dsi_dev->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET) val |= TC358768_DSI_CONTROL_EOTDIS; - tc358768_write(priv, TC358768_DSI_CONFW, val); + mask = TC358768_DSI_CONTROL_TXMD | TC358768_DSI_CONTROL_HSCKMD | + 0x3 << 1 | TC358768_DSI_CONTROL_EOTDIS; + + tc358768_confw_update_bits(priv, TC358768_DSI_CONTROL, mask, val); - val = TC358768_DSI_CONFW_MODE_CLR | TC358768_DSI_CONFW_ADDR_DSI_CONTROL; - val |= TC358768_DSI_CONTROL_DIS_MODE; /* DSI mode */ - tc358768_write(priv, TC358768_DSI_CONFW, val); + tc358768_confw_update_bits(priv, TC358768_DSI_CONTROL, + TC358768_DSI_CONTROL_DSI_MODE, 0); ret = tc358768_clear_error(priv); if (ret) dev_err(dev, "Bridge pre_enable failed: %d\n", ret); } +static void tc358768_config_video_format(struct tc358768_priv *priv) +{ + struct mipi_dsi_device *dsi_dev = priv->output.dev; + u32 val, data_type; + + /* Data Format Control Register */ + val = BIT(2) | BIT(1) | BIT(0); /* rdswap_en | dsitx_en | txdt_en */ + switch (dsi_dev->format) { + case MIPI_DSI_FMT_RGB888: + val |= (0x3 << 4); + data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; + break; + case MIPI_DSI_FMT_RGB666: + val |= (0x4 << 4); + data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18; + break; + case MIPI_DSI_FMT_RGB666_PACKED: + val |= (0x4 << 4) | BIT(3); + data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18; + break; + case MIPI_DSI_FMT_RGB565: + val |= (0x5 << 4); + data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; + break; + default: + dev_err(priv->dev, "Invalid data format (%u)\n", dsi_dev->format); + return; + } + + tc358768_write(priv, TC358768_DATAFMT, val); + tc358768_write(priv, TC358768_DSITX_DT, data_type); +} + static void tc358768_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_atomic_commit *state) { @@ -1101,6 +1205,14 @@ static void tc358768_bridge_atomic_enable(struct drm_bridge *bridge, return; } + /* Configure video format registers */ + tc358768_config_video_format(priv); + + /* Enable HS mode for video TX */ + tc358768_confw_update_bits(priv, TC358768_DSI_CONTROL, + TC358768_DSI_CONTROL_TXMD, + TC358768_DSI_CONTROL_TXMD); + /* clear FrmStop and RstPtr */ tc358768_update_bits(priv, TC358768_PP_MISC, 0x3 << 14, 0); diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 108953a8fa45..42b451432bbb 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -114,6 +114,7 @@ #define REG_VID_CHA_HORIZONTAL_FRONT_PORCH 0x38 #define REG_VID_CHA_VERTICAL_FRONT_PORCH 0x3a #define REG_VID_CHA_TEST_PATTERN 0x3c +#define REG_VID_CHA_TEST_PATTERN_EN BIT(4) /* IRQ registers */ #define REG_IRQ_GLOBAL 0xe0 #define REG_IRQ_GLOBAL_IRQ_EN BIT(0) @@ -134,6 +135,9 @@ #define REG_IRQ_STAT_CHA_SOT_BIT_ERR BIT(2) #define REG_IRQ_STAT_CHA_PLL_UNLOCK BIT(0) +static bool sn65dsi83_test_pattern; +module_param_named(test_pattern, sn65dsi83_test_pattern, bool, 0644); + enum sn65dsi83_channel { CHANNEL_A, CHANNEL_B @@ -523,6 +527,7 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, const struct drm_display_mode *mode; struct drm_connector *connector; struct drm_crtc *crtc; + bool test_pattern = sn65dsi83_test_pattern; bool lvds_format_24bpp; bool lvds_format_jeida; unsigned int pval; @@ -645,7 +650,11 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, REG_LVDS_LANE_CHB_LVDS_TERM : 0)); regmap_write(ctx->regmap, REG_LVDS_CM, 0x00); - le16val = cpu_to_le16(mode->hdisplay); + /* + * Active line length needs to be halved for test pattern + * generation in dual LVDS output. + */ + le16val = cpu_to_le16(mode->hdisplay / (test_pattern ? dual_factor : 1)); regmap_bulk_write(ctx->regmap, REG_VID_CHA_ACTIVE_LINE_LENGTH_LOW, &le16val, 2); le16val = cpu_to_le16(mode->vdisplay); @@ -668,7 +677,8 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, (mode->hsync_start - mode->hdisplay) / dual_factor); regmap_write(ctx->regmap, REG_VID_CHA_VERTICAL_FRONT_PORCH, mode->vsync_start - mode->vdisplay); - regmap_write(ctx->regmap, REG_VID_CHA_TEST_PATTERN, 0x00); + regmap_write(ctx->regmap, REG_VID_CHA_TEST_PATTERN, + test_pattern ? REG_VID_CHA_TEST_PATTERN_EN : 0); /* Enable PLL */ regmap_write(ctx->regmap, REG_RC_PLL_EN, REG_RC_PLL_EN_PLL_EN); diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 671b2bc75cb1..0884ec459cc5 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -776,8 +776,6 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge, goto err_initted_aux; } - drm_connector_attach_encoder(pdata->connector, pdata->bridge.encoder); - return 0; err_initted_aux: diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index 3b6b0e92cf89..bf4ab4eaf269 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -114,7 +114,7 @@ static void tfp410_hpd_callback(void *arg, enum drm_connector_status status) { struct tfp410 *dvi = arg; - mod_delayed_work(system_wq, &dvi->hpd_work, + mod_delayed_work(system_percpu_wq, &dvi->hpd_work, msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); } diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c index a23b7e33fba6..649969fca141 100644 --- a/drivers/gpu/drm/display/drm_bridge_connector.c +++ b/drivers/gpu/drm/display/drm_bridge_connector.c @@ -773,8 +773,11 @@ static void drm_bridge_connector_put_bridges(struct drm_device *dev, void *data) * @drm: the DRM device * @encoder: the encoder where the bridge chain starts * - * Allocate, initialise and register a &drm_bridge_connector with the @drm - * device. The connector is associated with a chain of bridges that starts at + * Create a new &drm_bridge_connector for the @drm device. The connector is + * allocated, initialised, registered with the @drm device and attached to + * @encoder. + * + * The connector is associated with a chain of bridges that starts at * the @encoder. All bridges in the chain shall report bridge operation flags * (&drm_bridge->ops) and bridge output type (&drm_bridge->type), and none of * them may create a DRM connector directly. @@ -1055,6 +1058,10 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, IS_ENABLED(CONFIG_DRM_DISPLAY_HDCP_HELPER)) drm_connector_attach_content_protection_property(connector, true); + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) + return ERR_PTR(ret); + return connector; } EXPORT_SYMBOL_GPL(drm_bridge_connector_init); diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 4ffa057e2784..170de30c28ae 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -463,19 +463,19 @@ static void drm_atomic_crtc_print_state(struct drm_printer *p, struct drm_crtc *crtc = state->crtc; drm_printf(p, "crtc[%u]: %s\n", crtc->base.id, crtc->name); - drm_printf(p, "\tenable=%d\n", state->enable); - drm_printf(p, "\tactive=%d\n", state->active); - drm_printf(p, "\tself_refresh_active=%d\n", state->self_refresh_active); - drm_printf(p, "\tplanes_changed=%d\n", state->planes_changed); - drm_printf(p, "\tmode_changed=%d\n", state->mode_changed); - drm_printf(p, "\tactive_changed=%d\n", state->active_changed); - drm_printf(p, "\tconnectors_changed=%d\n", state->connectors_changed); - drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed); - drm_printf(p, "\tplane_mask=%x\n", state->plane_mask); - drm_printf(p, "\tconnector_mask=%x\n", state->connector_mask); - drm_printf(p, "\tencoder_mask=%x\n", state->encoder_mask); - drm_printf(p, "\tmode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode)); - drm_printf(p, "\tbackground_color=%llx\n", state->background_color); + drm_printf_indent(p, 1, "enable=%d\n", state->enable); + drm_printf_indent(p, 1, "active=%d\n", state->active); + drm_printf_indent(p, 1, "self_refresh_active=%d\n", state->self_refresh_active); + drm_printf_indent(p, 1, "planes_changed=%d\n", state->planes_changed); + drm_printf_indent(p, 1, "mode_changed=%d\n", state->mode_changed); + drm_printf_indent(p, 1, "active_changed=%d\n", state->active_changed); + drm_printf_indent(p, 1, "connectors_changed=%d\n", state->connectors_changed); + drm_printf_indent(p, 1, "color_mgmt_changed=%d\n", state->color_mgmt_changed); + drm_printf_indent(p, 1, "plane_mask=%x\n", state->plane_mask); + drm_printf_indent(p, 1, "connector_mask=%x\n", state->connector_mask); + drm_printf_indent(p, 1, "encoder_mask=%x\n", state->encoder_mask); + drm_printf_indent(p, 1, "mode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode)); + drm_printf_indent(p, 1, "background_color=%llx\n", state->background_color); if (crtc->funcs->atomic_print_state) crtc->funcs->atomic_print_state(p, state); @@ -818,38 +818,38 @@ static void drm_atomic_colorop_print_state(struct drm_printer *p, struct drm_colorop *colorop = state->colorop; drm_printf(p, "colorop[%u]:\n", colorop->base.id); - drm_printf(p, "\ttype=%s\n", drm_get_colorop_type_name(colorop->type)); + drm_printf_indent(p, 1, "type=%s\n", drm_get_colorop_type_name(colorop->type)); if (colorop->bypass_property) - drm_printf(p, "\tbypass=%u\n", state->bypass); + drm_printf_indent(p, 1, "bypass=%u\n", state->bypass); switch (colorop->type) { case DRM_COLOROP_1D_CURVE: - drm_printf(p, "\tcurve_1d_type=%s\n", - drm_get_colorop_curve_1d_type_name(state->curve_1d_type)); + drm_printf_indent(p, 1, "curve_1d_type=%s\n", + drm_get_colorop_curve_1d_type_name(state->curve_1d_type)); break; case DRM_COLOROP_1D_LUT: - drm_printf(p, "\tsize=%d\n", colorop->size); - drm_printf(p, "\tinterpolation=%s\n", - drm_get_colorop_lut1d_interpolation_name(colorop->lut1d_interpolation)); - drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0); + drm_printf_indent(p, 1, "size=%d\n", colorop->size); + drm_printf_indent(p, 1, "interpolation=%s\n", + drm_get_colorop_lut1d_interpolation_name(colorop->lut1d_interpolation)); + drm_printf_indent(p, 1, "data blob id=%d\n", state->data ? state->data->base.id : 0); break; case DRM_COLOROP_CTM_3X4: - drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0); + drm_printf_indent(p, 1, "data blob id=%d\n", state->data ? state->data->base.id : 0); break; case DRM_COLOROP_MULTIPLIER: - drm_printf(p, "\tmultiplier=%llu\n", state->multiplier); + drm_printf_indent(p, 1, "multiplier=%llu\n", state->multiplier); break; case DRM_COLOROP_3D_LUT: - drm_printf(p, "\tsize=%d\n", colorop->size); - drm_printf(p, "\tinterpolation=%s\n", - drm_get_colorop_lut3d_interpolation_name(colorop->lut3d_interpolation)); - drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0); + drm_printf_indent(p, 1, "size=%d\n", colorop->size); + drm_printf_indent(p, 1, "interpolation=%s\n", + drm_get_colorop_lut3d_interpolation_name(colorop->lut3d_interpolation)); + drm_printf_indent(p, 1, "data blob id=%d\n", state->data ? state->data->base.id : 0); break; default: break; } - drm_printf(p, "\tnext=%d\n", colorop->next ? colorop->next->base.id : 0); + drm_printf_indent(p, 1, "next=%d\n", colorop->next ? colorop->next->base.id : 0); } static void drm_atomic_plane_print_state(struct drm_printer *p, @@ -860,21 +860,21 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, struct drm_rect dest = drm_plane_state_dest(state); drm_printf(p, "plane[%u]: %s\n", plane->base.id, plane->name); - drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); - drm_printf(p, "\tfb=%u\n", state->fb ? state->fb->base.id : 0); + drm_printf_indent(p, 1, "crtc=%s\n", state->crtc ? state->crtc->name : "(null)"); + drm_printf_indent(p, 1, "fb=%u\n", state->fb ? state->fb->base.id : 0); if (state->fb) drm_framebuffer_print_info(p, 2, state->fb); - drm_printf(p, "\tcrtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest)); - drm_printf(p, "\tsrc-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src)); - drm_printf(p, "\trotation=%x\n", state->rotation); - drm_printf(p, "\tnormalized-zpos=%x\n", state->normalized_zpos); - drm_printf(p, "\tcolor-encoding=%s\n", - drm_get_color_encoding_name(state->color_encoding)); - drm_printf(p, "\tcolor-range=%s\n", - drm_get_color_range_name(state->color_range)); - drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed); - drm_printf(p, "\tcolor-pipeline=%d\n", - state->color_pipeline ? state->color_pipeline->base.id : 0); + drm_printf_indent(p, 1, "crtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest)); + drm_printf_indent(p, 1, "src-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src)); + drm_printf_indent(p, 1, "rotation=%x\n", state->rotation); + drm_printf_indent(p, 1, "normalized-zpos=%x\n", state->normalized_zpos); + drm_printf_indent(p, 1, "color-encoding=%s\n", + drm_get_color_encoding_name(state->color_encoding)); + drm_printf_indent(p, 1, "color-range=%s\n", + drm_get_color_range_name(state->color_range)); + drm_printf_indent(p, 1, "color_mgmt_changed=%d\n", state->color_mgmt_changed); + drm_printf_indent(p, 1, "color-pipeline=%d\n", + state->color_pipeline ? state->color_pipeline->base.id : 0); if (plane->funcs->atomic_print_state) plane->funcs->atomic_print_state(p, state); } @@ -1347,27 +1347,27 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, struct drm_connector *connector = state->connector; drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name); - drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); - drm_printf(p, "\tself_refresh_aware=%d\n", state->self_refresh_aware); - drm_printf(p, "\tinterlace_allowed=%d\n", connector->interlace_allowed); - drm_printf(p, "\tycbcr_420_allowed=%d\n", connector->ycbcr_420_allowed); - drm_printf(p, "\tmax_requested_bpc=%d\n", state->max_requested_bpc); - drm_printf(p, "\tcolorspace=%s\n", drm_get_colorspace_name(state->colorspace)); + drm_printf_indent(p, 1, "crtc=%s\n", state->crtc ? state->crtc->name : "(null)"); + drm_printf_indent(p, 1, "self_refresh_aware=%d\n", state->self_refresh_aware); + drm_printf_indent(p, 1, "interlace_allowed=%d\n", connector->interlace_allowed); + drm_printf_indent(p, 1, "ycbcr_420_allowed=%d\n", connector->ycbcr_420_allowed); + drm_printf_indent(p, 1, "max_requested_bpc=%d\n", state->max_requested_bpc); + drm_printf_indent(p, 1, "colorspace=%s\n", drm_get_colorspace_name(state->colorspace)); if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) { - drm_printf(p, "\tbroadcast_rgb=%s\n", - drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb)); - drm_printf(p, "\tis_limited_range=%c\n", state->hdmi.is_limited_range ? 'y' : 'n'); - drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc); - drm_printf(p, "\toutput_format=%s\n", - drm_hdmi_connector_get_output_format_name(state->hdmi.output_format)); - drm_printf(p, "\ttmds_char_rate=%llu\n", state->hdmi.tmds_char_rate); + drm_printf_indent(p, 1, "broadcast_rgb=%s\n", + drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb)); + drm_printf_indent(p, 1, "is_limited_range=%c\n", state->hdmi.is_limited_range ? 'y' : 'n'); + drm_printf_indent(p, 1, "output_bpc=%u\n", state->hdmi.output_bpc); + drm_printf_indent(p, 1, "output_format=%s\n", + drm_hdmi_connector_get_output_format_name(state->hdmi.output_format)); + drm_printf_indent(p, 1, "tmds_char_rate=%llu\n", state->hdmi.tmds_char_rate); } if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) if (state->writeback_job && state->writeback_job->fb) - drm_printf(p, "\tfb=%d\n", state->writeback_job->fb->base.id); + drm_printf_indent(p, 1, "fb=%d\n", state->writeback_job->fb->base.id); if (connector->funcs->atomic_print_state) connector->funcs->atomic_print_state(p, state); diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index e17bb0f1f9e0..e5013b870ba0 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -347,7 +347,7 @@ void drm_master_release(struct drm_file *file_priv) if (!drm_is_current_master_locked(file_priv)) goto out; - if (dev->master == file_priv->master) + if (dev->master && dev->master == file_priv->master) drm_drop_master(dev, file_priv); out: if (drm_core_check_feature(dev, DRIVER_MODESET) && file_priv->is_master) { diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index d33ca2099135..ce180f0b26b2 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -1614,18 +1614,17 @@ static void drm_bridge_debugfs_show_bridge(struct drm_printer *p, drm_printf(p, "bridge[%u]: %ps\n", idx, bridge->funcs); - drm_printf(p, "\trefcount: %u%s\n", refcount, - lingering ? " [lingering]" : ""); + drm_printf_indent(p, 1, "refcount: %u%s\n", refcount, + lingering ? " [lingering]" : ""); - drm_printf(p, "\ttype: [%d] %s\n", - bridge->type, - drm_get_connector_type_name(bridge->type)); + drm_printf_indent(p, 1, "type: [%d] %s\n", bridge->type, + drm_get_connector_type_name(bridge->type)); /* The OF node could be freed after drm_bridge_remove() */ if (bridge->of_node && !lingering) - drm_printf(p, "\tOF: %pOFfc\n", bridge->of_node); + drm_printf_indent(p, 1, "OF: %pOFfc\n", bridge->of_node); - drm_printf(p, "\tops: [0x%x]", bridge->ops); + drm_printf_indent(p, 1, "ops: [0x%x]", bridge->ops); if (bridge->ops & DRM_BRIDGE_OP_DETECT) drm_puts(p, " detect"); if (bridge->ops & DRM_BRIDGE_OP_EDID) diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index e0d533611040..60cd02b7ea64 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -275,6 +275,7 @@ const struct drm_format_info *__drm_format_info(u32 format) { .format = DRM_FORMAT_YVU422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_YUV444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_YVU444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_Y8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_NV12, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true }, { .format = DRM_FORMAT_NV21, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true }, { .format = DRM_FORMAT_NV16, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, @@ -287,6 +288,7 @@ const struct drm_format_info *__drm_format_info(u32 format) { .format = DRM_FORMAT_VYUY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_XYUV8888, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_VUY888, .depth = 0, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_XVUY2101010, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true }, { .format = DRM_FORMAT_Y210, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_Y212, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, @@ -354,6 +356,9 @@ const struct drm_format_info *__drm_format_info(u32 format) { .format = DRM_FORMAT_P030, .depth = 0, .num_planes = 2, .char_per_block = { 4, 8, 0 }, .block_w = { 3, 3, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true}, + { .format = DRM_FORMAT_P230, .depth = 0, .num_planes = 2, + .char_per_block = { 4, 8, 0 }, .block_w = { 3, 3, 0 }, .block_h = { 1, 1, 0 }, + .hsub = 2, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_S010, .depth = 0, .num_planes = 3, .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 2, .vsub = 2, .is_yuv = true}, @@ -381,6 +386,12 @@ const struct drm_format_info *__drm_format_info(u32 format) { .format = DRM_FORMAT_S416, .depth = 0, .num_planes = 3, .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 1, .vsub = 1, .is_yuv = true}, + { .format = DRM_FORMAT_XYYY2101010, .depth = 0, .num_planes = 1, + .char_per_block = { 4, 0, 0 }, .block_w = { 3, 0, 0 }, .block_h = { 1, 0, 0 }, + .hsub = 1, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_T430, .depth = 0, .num_planes = 3, + .char_per_block = { 4, 4, 4 }, .block_w = { 3, 3, 3 }, .block_h = { 1, 1, 1 }, + .hsub = 1, .vsub = 1, .is_yuv = true }, }; unsigned int i; @@ -491,12 +502,20 @@ EXPORT_SYMBOL(drm_format_info_block_height); */ unsigned int drm_format_info_bpp(const struct drm_format_info *info, int plane) { + unsigned int block_size; + if (!info || plane < 0 || plane >= info->num_planes) return 0; - return info->char_per_block[plane] * 8 / - (drm_format_info_block_width(info, plane) * - drm_format_info_block_height(info, plane)); + block_size = drm_format_info_block_width(info, plane) * + drm_format_info_block_height(info, plane); + + if (info->char_per_block[plane] * 8 % block_size) { + pr_warn("unable to return an integer bpp\n"); + return 0; + } + + return info->char_per_block[plane] * 8 / block_size; } EXPORT_SYMBOL(drm_format_info_bpp); diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 0390e14d3157..3ac1dd5ad640 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -587,6 +587,9 @@ EXPORT_SYMBOL(mipi_dsi_create_packet); * mipi_dsi_shutdown_peripheral() - sends a Shutdown Peripheral command * @dsi: DSI peripheral device * + * This function is deprecated. Use mipi_dsi_shutdown_peripheral_multi() + * instead. + * * Return: 0 on success or a negative error code on failure. */ int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi) @@ -1980,6 +1983,31 @@ void mipi_dsi_dcs_set_tear_scanline_multi(struct mipi_dsi_multi_context *ctx, } EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_scanline_multi); +/** + * mipi_dsi_shutdown_peripheral_multi() - sends a Shutdown Peripheral command + * @ctx: Context for multiple DSI transactions + * + * Like mipi_dsi_shutdown_peripheral() but deals with errors in a way that + * makes it convenient to make several calls in a row. + */ +void mipi_dsi_shutdown_peripheral_multi(struct mipi_dsi_multi_context *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + if (ctx->accum_err) + return; + + ret = mipi_dsi_shutdown_peripheral(dsi); + if (ret < 0) { + ctx->accum_err = ret; + dev_err(dev, "Failed to shutdown peripheral: %d\n", + ctx->accum_err); + } +} +EXPORT_SYMBOL(mipi_dsi_shutdown_peripheral_multi); + static int mipi_dsi_drv_probe(struct device *dev) { struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h index 20dad16fd554..55a9e745604d 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h @@ -94,18 +94,6 @@ void etnaviv_gem_describe_objects(struct etnaviv_drm_private *priv, #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) /* - * Return the storage size of a structure with a variable length array. - * The array is nelem elements of elem_size, where the base structure - * is defined by base. If the size overflows size_t, return zero. - */ -static inline size_t size_vstruct(size_t nelem, size_t elem_size, size_t base) -{ - if (elem_size && nelem > (SIZE_MAX - base) / elem_size) - return 0; - return base + nelem * elem_size; -} - -/* * Etnaviv timeouts are specified wrt CLOCK_MONOTONIC, not jiffies. * We need to calculate the timeout in terms of number of jiffies * between the specified timeout and the current CLOCK_MONOTONIC time. diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index fbf693addd74..1a77a09b3377 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -32,9 +32,8 @@ static struct etnaviv_gem_submit *submit_create(struct drm_device *dev, struct etnaviv_gpu *gpu, size_t nr_bos, size_t nr_pmrs) { struct etnaviv_gem_submit *submit; - size_t sz = size_vstruct(nr_bos, sizeof(submit->bos[0]), sizeof(*submit)); - submit = kzalloc(sz, GFP_KERNEL); + submit = kzalloc_flex(*submit, bos, nr_bos); if (!submit) return NULL; diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index 6884ea6d04eb..b80540328150 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c @@ -118,7 +118,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) return ret; } - return drm_connector_attach_encoder(connector, dp->plat_data.encoder); + return 0; } static void exynos_dp_unbind(struct device *dev, struct device *master, diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 005ab7f5355f..947f7c4ff4e9 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -24,7 +24,6 @@ #include <drm/drm_drv.h> #include <drm/drm_file.h> #include <drm/drm_ioctl.h> -#include <drm/drm_pciids.h> #include <drm/drm_print.h> #include <drm/drm_vblank.h> diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c index 051ecc526832..753d97bff76f 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c @@ -10,7 +10,7 @@ #include "hyperv_drm.h" -#define VMBUS_RING_BUFSIZE (256 * 1024) +#define VMBUS_RING_BUFSIZE VMBUS_RING_SIZE(256 * 1024) #define VMBUS_VSP_TIMEOUT (10 * HZ) #define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major)) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 65ce54b20ec2..05997e8bbb29 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -3205,8 +3205,7 @@ eb_composite_fence_create(struct i915_execbuffer *eb, int out_fence_fd) fence_array = dma_fence_array_create(eb->num_batches, fences, eb->context->parallel.fence_context, - eb->context->parallel.seqno++, - false); + eb->context->parallel.seqno++); if (!fence_array) { kfree(fences); return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.c b/drivers/gpu/drm/imagination/pvr_fw_trace.c index 6193811ef7be..6bb5baa6c41b 100644 --- a/drivers/gpu/drm/imagination/pvr_fw_trace.c +++ b/drivers/gpu/drm/imagination/pvr_fw_trace.c @@ -77,7 +77,7 @@ const struct kernel_param_ops pvr_fw_trace_init_mask_ops = { }; param_check_hexint(init_fw_trace_mask, &pvr_fw_trace_init_mask); -module_param_cb(init_fw_trace_mask, &pvr_fw_trace_init_mask_ops, &pvr_fw_trace_init_mask, 0600); +module_param_cb(init_fw_trace_mask, &pvr_fw_trace_init_mask_ops, &pvr_fw_trace_init_mask, 0400); __MODULE_PARM_TYPE(init_fw_trace_mask, "hexint"); MODULE_PARM_DESC(init_fw_trace_mask, "Enable FW trace for the specified groups at device init time"); diff --git a/drivers/gpu/drm/imx/dc/dc-kms.c b/drivers/gpu/drm/imx/dc/dc-kms.c index 2b18aa37a4a8..0f8cfaf4c4d1 100644 --- a/drivers/gpu/drm/imx/dc/dc-kms.c +++ b/drivers/gpu/drm/imx/dc/dc-kms.c @@ -81,13 +81,7 @@ static int dc_kms_init_encoder_per_crtc(struct dc_drm_device *dc_drm, return ret; } - ret = drm_connector_attach_encoder(connector, encoder); - if (ret) - dev_err(dev, - "failed to attach encoder to connector for CRTC%u: %d\n", - crtc->index, ret); - - return ret; + return 0; } int dc_kms_init(struct dc_drm_device *dc_drm) diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.c b/drivers/gpu/drm/imx/dcss/dcss-kms.c index 3633e8f3aff6..50bd7f36d36d 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-kms.c +++ b/drivers/gpu/drm/imx/dcss/dcss-kms.c @@ -103,8 +103,6 @@ static int dcss_kms_bridge_connector_init(struct dcss_kms_dev *kms) return PTR_ERR(kms->connector); } - drm_connector_attach_encoder(kms->connector, encoder); - return 0; } diff --git a/drivers/gpu/drm/imx/ipuv3/Kconfig b/drivers/gpu/drm/imx/ipuv3/Kconfig index 351dc65913eb..3ca237515e46 100644 --- a/drivers/gpu/drm/imx/ipuv3/Kconfig +++ b/drivers/gpu/drm/imx/ipuv3/Kconfig @@ -13,6 +13,7 @@ config DRM_IMX config DRM_IMX_PARALLEL_DISPLAY tristate "Support for parallel displays" depends on DRM_IMX + depends on OF select DRM_BRIDGE select DRM_BRIDGE_CONNECTOR select DRM_DISPLAY_HELPER @@ -33,6 +34,7 @@ config DRM_IMX_LDB tristate "Support for LVDS displays" depends on DRM_IMX depends on COMMON_CLK + depends on OF select MFD_SYSCON select DRM_BRIDGE select DRM_BRIDGE_CONNECTOR diff --git a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c index 730caf883e83..63d6a1e7c1bd 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c +++ b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c @@ -407,8 +407,6 @@ static int imx_ldb_register(struct drm_device *drm, if (IS_ERR(connector)) return PTR_ERR(connector); - drm_connector_attach_encoder(connector, encoder); - return 0; } diff --git a/drivers/gpu/drm/imx/ipuv3/parallel-display.c b/drivers/gpu/drm/imx/ipuv3/parallel-display.c index 6c505becb31d..0f06db95f00f 100644 --- a/drivers/gpu/drm/imx/ipuv3/parallel-display.c +++ b/drivers/gpu/drm/imx/ipuv3/parallel-display.c @@ -216,8 +216,6 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) if (IS_ERR(connector)) return PTR_ERR(connector); - drm_connector_attach_encoder(connector, encoder); - return 0; } diff --git a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c index e200b40f30fe..f52832b43aca 100644 --- a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c +++ b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c @@ -448,8 +448,6 @@ static int imx_lcdc_probe(struct platform_device *pdev) if (IS_ERR(lcdc->connector)) return dev_err_probe(drm->dev, PTR_ERR(lcdc->connector), "Cannot init bridge connector\n"); - drm_connector_attach_encoder(lcdc->connector, &lcdc->pipe.encoder); - /* * The LCDC controller does not have an enable bit. The * controller starts directly when the clocks are enabled. diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index 2350c9499aef..42c86f195c66 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -1330,8 +1330,6 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) ret = PTR_ERR(connector); goto err_drvdata; } - - drm_connector_attach_encoder(connector, encoder); } drm_for_each_encoder(encoder, drm) { diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index 4b5a9c051e65..59d0e856392f 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -1457,7 +1457,7 @@ int kmb_dsi_encoder_init(struct drm_device *dev, struct kmb_dsi *kmb_dsi) drm_encoder_cleanup(encoder); return PTR_ERR(connector); } - drm_connector_attach_encoder(connector, encoder); + return 0; } diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c index 53360b5d12ba..cc6d74ce8b5e 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -1049,7 +1049,6 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data) ret = PTR_ERR(dpi->connector); goto err_cleanup; } - drm_connector_attach_encoder(dpi->connector, &dpi->encoder); return 0; diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index dacc36ccb731..46cf4b043f12 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -936,7 +936,6 @@ static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi) ret = PTR_ERR(dsi->connector); goto err_cleanup_encoder; } - drm_connector_attach_encoder(dsi->connector, &dsi->encoder); return 0; diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c index 574ffffd4a27..8b26a0031cde 100644 --- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c +++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c @@ -279,8 +279,6 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv) return dev_err_probe(priv->dev, PTR_ERR(connector), "Unable to create CVBS bridge connector\n"); - drm_connector_attach_encoder(connector, &meson_encoder_cvbs->encoder); - priv->encoders[MESON_ENC_CVBS] = meson_encoder_cvbs; return 0; diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c index d766625aa1d0..55c0601df3c6 100644 --- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c @@ -433,8 +433,6 @@ int meson_encoder_hdmi_probe(struct meson_drm *priv) "Unable to create HDMI bridge connector\n"); goto err_put_node; } - drm_connector_attach_encoder(meson_encoder_hdmi->connector, - &meson_encoder_hdmi->encoder); /* * We should have now in place: diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index a32be27c39e8..d7b5dfdb28aa 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -19,7 +19,6 @@ #include <drm/drm_ioctl.h> #include <drm/drm_managed.h> #include <drm/drm_module.h> -#include <drm/drm_pciids.h> #include <drm/drm_print.h> #include "mgag200_drv.h" diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c index 809ca191e9de..7726edb0d4ed 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c @@ -232,13 +232,6 @@ static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms, return PTR_ERR(connector); } - ret = drm_connector_attach_encoder(connector, encoder); - if (ret) { - DRM_DEV_ERROR(dev->dev, "failed to attach LVDS connector: %d\n", ret); - - return ret; - } - break; case DRM_MODE_ENCODER_TMDS: encoder = mdp4_dtv_encoder_init(dev); diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index ec4652e620c4..349175457566 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -376,7 +376,5 @@ struct drm_connector *msm_dp_drm_connector_init(struct msm_dp *msm_dp_display, if (!msm_dp_display->is_edp) drm_connector_attach_dp_subconnector_property(connector); - drm_connector_attach_encoder(connector, encoder); - return connector; } diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index ca400924d4ee..46faeaae9d94 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -485,10 +485,6 @@ int msm_dsi_manager_connector_init(struct msm_dsi *msm_dsi, return PTR_ERR(connector); } - ret = drm_connector_attach_encoder(connector, encoder); - if (ret < 0) - return ret; - return 0; } diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 852abb2466f0..d9491aac1a89 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -190,8 +190,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi, goto fail; } - drm_connector_attach_encoder(hdmi->connector, hdmi->encoder); - ret = devm_request_irq(dev->dev, hdmi->irq, msm_hdmi_irq, IRQF_TRIGGER_HIGH, "hdmi_isr", hdmi); diff --git a/drivers/gpu/drm/mxsfb/lcdif_drv.c b/drivers/gpu/drm/mxsfb/lcdif_drv.c index 7f07ae24e0dc..f5bb59cd5028 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_drv.c +++ b/drivers/gpu/drm/mxsfb/lcdif_drv.c @@ -99,12 +99,6 @@ static int lcdif_attach_bridge(struct lcdif_drm_private *lcdif) return dev_err_probe(dev, PTR_ERR(connector), "Failed to init bridge_connector for endpoint%u\n", of_ep.id); - - ret = drm_connector_attach_encoder(connector, encoder); - if (ret) - return dev_err_probe(dev, ret, - "Failed to attach connector for endpoint%u\n", - of_ep.id); } return 0; diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index b983f4f9bcd7..364227f5456f 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -2474,7 +2474,7 @@ nv50_disp_atomic_commit(struct drm_device *dev, pm_runtime_get_noresume(dev->dev); if (nonblock) - queue_work(system_unbound_wq, &state->commit_work); + queue_work(system_dfl_wq, &state->commit_work); else nv50_disp_atomic_commit_tail(state); diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index c8335f5b49db..38032bb95826 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -2085,10 +2085,27 @@ nouveau_bios_init(struct drm_device *dev) int ret; /* only relevant for PCI devices */ - if (!dev_is_pci(dev->dev) || - nvkm_gsp_rm(nvxx_device(drm)->gsp)) + if (!dev_is_pci(dev->dev)) return 0; + if (nvkm_gsp_rm(nvxx_device(drm)->gsp)) { + struct nvkm_bios *nvkm_bios = nvxx_bios(drm); + + /* + * If this GPU has an nvkm_device_chip.bios entry, then the VBIOS + * data was already read by the nvkm layer during nvkm_bios_new(). + * Point the legacy DRM-level VBIOS structure at the same buffer + * so that any remaining legacy code can access it. This exposes + * the VBIOS via the DRM debugfs entries. + */ + if (nvkm_bios) { + bios->data = nvkm_bios->data; + bios->length = nvkm_bios->size; + } + + return 0; + } + if (!NVInitVBIOS(dev)) return -ENODEV; diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 517ff2c31dce..e16f59b00f6f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -632,7 +632,7 @@ nouveau_drm_device_init(struct nouveau_drm *drm) struct drm_device *dev = drm->dev; int ret; - drm->sched_wq = alloc_workqueue("nouveau_sched_wq_shared", 0, + drm->sched_wq = alloc_workqueue("nouveau_sched_wq_shared", WQ_PERCPU, WQ_MAX_ACTIVE); if (!drm->sched_wq) return -ENOMEM; diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.c b/drivers/gpu/drm/nouveau/nouveau_sched.c index 179edf90a531..2cbae003d6de 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.c +++ b/drivers/gpu/drm/nouveau/nouveau_sched.c @@ -413,7 +413,8 @@ nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm, int ret; if (!wq) { - wq = alloc_workqueue("nouveau_sched_wq_%d", 0, WQ_MAX_ACTIVE, + wq = alloc_workqueue("nouveau_sched_wq_%d", WQ_PERCPU, + WQ_MAX_ACTIVE, current->pid); if (!wq) return -ENOMEM; diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 2042a633835f..92d6a1f9c0a1 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -507,8 +507,6 @@ static int omap_modeset_init(struct drm_device *dev) return PTR_ERR(pipe->connector); } - drm_connector_attach_encoder(pipe->connector, encoder); - crtc = omap_crtc_init(dev, pipe, priv->planes[i]); if (IS_ERR(crtc)) return PTR_ERR(crtc); diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 979109c27b9b..b0e9b92e2c84 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -105,8 +105,20 @@ config DRM_PANEL_BOE_TV101WUM_LL2 Say Y here if you want to support for BOE TV101WUM-LL2 WUXGA PANEL DSI Video Mode panel +config DRM_PANEL_CHIPWEALTH_CH13726A + tristate "CHIPWEALTH CH13726A-based DSI panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_HELPER + help + Say Y here if you want to enable support for ChipWealth + CH13726A-based display panels. + config DRM_PANEL_EBBG_FT8719 tristate "EBBG FT8719 panel driver" + depends on GPIOLIB depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE @@ -357,7 +369,8 @@ config DRM_PANEL_JADARD_JD9365DA_H3 config DRM_PANEL_JDI_LPM102A188A tristate "JDI LPM102A188A DSI panel" - depends on OF && GPIOLIB + depends on GPIOLIB + depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE help @@ -472,6 +485,7 @@ config DRM_PANEL_LG_LG4573 config DRM_PANEL_LG_SW43408 tristate "LG SW43408 panel" + depends on GPIOLIB depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE @@ -562,6 +576,16 @@ config DRM_PANEL_NOVATEK_NT35510 around the Novatek NT35510 display controller, such as some Hydis panels. +config DRM_PANEL_NOVATEK_NT35532 + tristate "Novatek NT35532-based DSI video mode panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + select DRM_KMS_HELPER + help + Say Y or M here if you want to enable support for Novatek + NT35532-based 1080p video mode DSI panels. + config DRM_PANEL_NOVATEK_NT35560 tristate "Novatek NT35560 DSI command mode panel" depends on OF @@ -597,6 +621,7 @@ config DRM_PANEL_NOVATEK_NT36523 config DRM_PANEL_NOVATEK_NT36672A tristate "Novatek NT36672A DSI panel" + depends on GPIOLIB depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE @@ -607,6 +632,7 @@ config DRM_PANEL_NOVATEK_NT36672A config DRM_PANEL_NOVATEK_NT36672E tristate "Novatek NT36672E DSI panel" + depends on GPIOLIB depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE @@ -744,7 +770,8 @@ config DRM_PANEL_RAYDIUM_RM692E5 config DRM_PANEL_RAYDIUM_RM69380 tristate "Raydium RM69380-based DSI panel" - depends on OF && GPIOLIB + depends on GPIOLIB + depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE help @@ -902,10 +929,10 @@ config DRM_PANEL_SAMSUNG_S6D7AA0 config DRM_PANEL_SAMSUNG_S6E3FC2X01 tristate "Samsung S6E3FC2X01 DSI panel controller" + depends on GPIOLIB depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE - select VIDEOMODE_HELPERS help Say Y or M here if you want to enable support for the Samsung S6E3FC2 DDIC and connected MIPI DSI panel. @@ -922,11 +949,18 @@ config DRM_PANEL_SAMSUNG_S6E3HA2 config DRM_PANEL_SAMSUNG_S6E3HA8 tristate "Samsung S6E3HA8 DSI video mode panel" + depends on GPIOLIB depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE select DRM_DISPLAY_DSC_HELPER - select VIDEOMODE_HELPERS + help + Say Y or M here if you want to enable support for the + Samsung S6E3HA8 DDIC and connected MIPI DSI panel. + Currently supported panels: + + Samsung AMB577PX01 (found in the Samsung S9 smartphone) + config DRM_PANEL_SAMSUNG_S6E63J0X03 tristate "Samsung S6E63J0X03 DSI command mode panel" @@ -994,10 +1028,10 @@ config DRM_PANEL_SAMSUNG_S6E8FC0 config DRM_PANEL_SAMSUNG_SOFEF00 tristate "Samsung SOFEF00 DSI panel controller" + depends on GPIOLIB depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE - select VIDEOMODE_HELPERS help Say Y or M here if you want to enable support for the Samsung AMOLED panel SOFEF00 DDIC and connected panel. @@ -1262,6 +1296,7 @@ config DRM_PANEL_VISIONOX_R66451 config DRM_PANEL_VISIONOX_RM69299 tristate "Visionox RM69299" + depends on GPIOLIB depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 0d694acbfbb6..c2c5cf817116 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_DRM_PANEL_BOE_TD4320) += panel-boe-td4320.o obj-$(CONFIG_DRM_PANEL_BOE_TH101MB31UIG002_28A) += panel-boe-th101mb31ig002-28a.o obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_LL2) += panel-boe-tv101wum-ll2.o obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_NL6) += panel-boe-tv101wum-nl6.o +obj-$(CONFIG_DRM_PANEL_CHIPWEALTH_CH13726A) += panel-chipwealth-ch13726a.o obj-$(CONFIG_DRM_PANEL_DSI_CM) += panel-dsi-cm.o obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o @@ -55,6 +56,7 @@ obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3051D) += panel-newvision-nv3051d.o obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3052C) += panel-newvision-nv3052c.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35510) += panel-novatek-nt35510.o +obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35532) += panel-novatek-nt35532.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35560) += panel-novatek-nt35560.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35950) += panel-novatek-nt35950.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36523) += panel-novatek-nt36523.o diff --git a/drivers/gpu/drm/panel/panel-chipwealth-ch13726a.c b/drivers/gpu/drm/panel/panel-chipwealth-ch13726a.c new file mode 100644 index 000000000000..be76bc825c3f --- /dev/null +++ b/drivers/gpu/drm/panel/panel-chipwealth-ch13726a.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ChipWealth CH13726A MIPI-DSI panel driver + * Copyright (c) 2024, Teguh Sobirin <teguh@sobir.in>. + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +#include <video/mipi_display.h> + +static const struct regulator_bulk_data ch13726a_supplies[] = { + { .supply = "vdd1v2", }, + { .supply = "vddio", }, + { .supply = "vdd", }, + { .supply = "avdd", }, +}; + +struct ch13726a_panel { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct regulator_bulk_data *supplies; + struct gpio_desc *reset_gpio; + struct ch13726a_desc *desc; + enum drm_panel_orientation orientation; +}; + +struct ch13726a_desc { + unsigned int width_mm; + unsigned int height_mm; + unsigned int bpc; + + const struct drm_display_mode *modes; + unsigned int num_modes; +}; + +static inline struct ch13726a_panel *to_ch13726a_panel(struct drm_panel *panel) +{ + return container_of(panel, struct ch13726a_panel, panel); +} + +static void ch13726a_reset(struct ch13726a_panel *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); +} + +static int ch13726a_on(struct ch13726a_panel *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x50); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb9, 0x00); + + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); + + return dsi_ctx.accum_err; +} + +static int ch13726a_disable(struct drm_panel *panel) +{ + struct ch13726a_panel *ctx = to_ch13726a_panel(panel); + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 50); + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + + return dsi_ctx.accum_err; +} + +static int ch13726a_prepare(struct drm_panel *panel) +{ + struct ch13726a_panel *ctx = to_ch13726a_panel(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ch13726a_supplies), ctx->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + ch13726a_reset(ctx); + + ret = ch13726a_on(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ch13726a_supplies), ctx->supplies); + return ret; + } + + msleep(28); + + return 0; +} + +static int ch13726a_unprepare(struct drm_panel *panel) +{ + struct ch13726a_panel *ctx = to_ch13726a_panel(panel); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ch13726a_supplies), ctx->supplies); + + return 0; +} + +static const struct drm_display_mode thor_bottom_modes[] = { + { + /* 120Hz */ + .clock = (1080 + 28 + 4 + 36) * (1240 + 16 + 4 + 8) * 120 / 1000, + .hdisplay = 1080, + .hsync_start = 1080 + 28, + .hsync_end = 1080 + 28 + 4, + .htotal = 1080 + 28 + 4 + 36, + .vdisplay = 1240, + .vsync_start = 1240 + 16, + .vsync_end = 1240 + 16 + 4, + .vtotal = 1240 + 16 + 4 + 8, + }, + { + /* 60Hz */ + .clock = (1080 + 28 + 4 + 36) * (1240 + 16 + 4 + 8) * 60 / 1000, + .hdisplay = 1080, + .hsync_start = 1080 + 28, + .hsync_end = 1080 + 28 + 4, + .htotal = 1080 + 28 + 4 + 36, + .vdisplay = 1240, + .vsync_start = 1240 + 16, + .vsync_end = 1240 + 16 + 4, + .vtotal = 1240 + 16 + 4 + 8, + } +}; + +static struct ch13726a_desc thor_bottom_desc = { + .modes = thor_bottom_modes, + .num_modes = ARRAY_SIZE(thor_bottom_modes), + .width_mm = 65, + .height_mm = 75, + .bpc = 8, +}; + +static int ch13726a_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct ch13726a_panel *ctx = to_ch13726a_panel(panel); + + for (uint8_t i = 0; i < ctx->desc->num_modes; i++) { + const struct drm_display_mode *m = &ctx->desc->modes[i]; + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, m); + if (!mode) { + dev_err(&ctx->dsi->dev, "failed to add mode %ux%u@%u\n", + m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); + return -ENOMEM; + } + + mode->type = DRM_MODE_TYPE_DRIVER; + if (i == 0) + mode->type |= DRM_MODE_TYPE_PREFERRED; + + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + } + + connector->display_info.width_mm = ctx->desc->width_mm; + connector->display_info.height_mm = ctx->desc->height_mm; + connector->display_info.bpc = ctx->desc->bpc; + + return ctx->desc->num_modes; +} + +static enum drm_panel_orientation ch13726a_get_orientation(struct drm_panel *panel) +{ + struct ch13726a_panel *ctx = to_ch13726a_panel(panel); + + return ctx->orientation; +} + +static const struct drm_panel_funcs ch13726a_panel_funcs = { + .prepare = ch13726a_prepare, + .unprepare = ch13726a_unprepare, + .disable = ch13726a_disable, + .get_modes = ch13726a_get_modes, + .get_orientation = ch13726a_get_orientation, +}; + +static int ch13726a_bl_update_status(struct backlight_device *bl) +{ + struct mipi_dsi_device *dsi = bl_get_data(bl); + u16 brightness = backlight_get_brightness(bl); + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_set_display_brightness(dsi, brightness); + if (ret < 0) + return ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + return 0; +} + +static const struct backlight_ops ch13726a_bl_ops = { + .update_status = ch13726a_bl_update_status, +}; + +static struct backlight_device * +ch13726a_create_backlight(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = 255, + .max_brightness = 255, + }; + + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, + &ch13726a_bl_ops, &props); +} + +static int ch13726a_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct ch13726a_panel *ctx; + int ret; + + ctx = devm_drm_panel_alloc(dev, __typeof(*ctx), panel, + &ch13726a_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ctx->desc = (struct ch13726a_desc *)of_device_get_match_data(dev); + if (!ctx->desc) + return -ENODEV; + + ret = devm_regulator_bulk_get_const(dev, + ARRAY_SIZE(ch13726a_supplies), + ch13726a_supplies, + &ctx->supplies); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), + "Failed to get reset-gpios\n"); + + ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation); + if (ret < 0) { + dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret); + return ret; + } + + ctx->dsi = dsi; + mipi_dsi_set_drvdata(dsi, ctx); + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | + MIPI_DSI_CLOCK_NON_CONTINUOUS; + + ctx->panel.prepare_prev_first = true; + + ctx->panel.backlight = ch13726a_create_backlight(dsi); + if (IS_ERR(ctx->panel.backlight)) + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), + "Failed to create backlight\n"); + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + dev_err(dev, "Failed to attach to DSI host: %d\n", ret); + drm_panel_remove(&ctx->panel); + return ret; + } + + return 0; +} + +static void ch13726a_remove(struct mipi_dsi_device *dsi) +{ + struct ch13726a_panel *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + + ret = mipi_dsi_detach(dsi); + if (ret < 0) + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); + + drm_panel_remove(&ctx->panel); +} + +static const struct of_device_id ch13726a_of_match[] = { + { .compatible = "ayntec,thor-panel-bottom", .data = &thor_bottom_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ch13726a_of_match); + +static struct mipi_dsi_driver ch13726a_driver = { + .probe = ch13726a_probe, + .remove = ch13726a_remove, + .driver = { + .name = "panel-ch13726a-amoled", + .of_match_table = ch13726a_of_match, + }, +}; +module_mipi_dsi_driver(ch13726a_driver); + +MODULE_DESCRIPTION("DRM driver for CH13726A DSI panels"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-focaltech-ota7290b.c b/drivers/gpu/drm/panel/panel-focaltech-ota7290b.c index dd420bb19440..ed02a8daf96f 100644 --- a/drivers/gpu/drm/panel/panel-focaltech-ota7290b.c +++ b/drivers/gpu/drm/panel/panel-focaltech-ota7290b.c @@ -156,8 +156,8 @@ static int ota7290b_probe(struct mipi_dsi_device *dsi) ctx = devm_drm_panel_alloc(&dsi->dev, struct ota7290b, panel, &ota7290b_funcs, DRM_MODE_CONNECTOR_DSI); - if (!ctx) - return -ENOMEM; + if (IS_ERR(ctx)) + return PTR_ERR(ctx); mipi_dsi_set_drvdata(dsi, ctx); ctx->dsi = dsi; diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index 947b47841b01..0652cdb57d11 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -52,6 +52,7 @@ struct ili9881c { const struct ili9881c_desc *desc; struct regulator *power; + struct regulator *iovcc; struct gpio_desc *reset; enum drm_panel_orientation orientation; @@ -1997,6 +1998,205 @@ static const struct ili9881c_instr bsd1218_a101kl68_init[] = { ILI9881C_COMMAND_INSTR(0xd3, 0x3f), }; +static const struct ili9881c_instr waveshare_7inch_a_init[] = { + ILI9881C_SWITCH_PAGE_INSTR(3), + ILI9881C_COMMAND_INSTR(0x01, 0x00), + ILI9881C_COMMAND_INSTR(0x02, 0x00), + ILI9881C_COMMAND_INSTR(0x03, 0x73), + ILI9881C_COMMAND_INSTR(0x04, 0x00), + ILI9881C_COMMAND_INSTR(0x05, 0x00), + ILI9881C_COMMAND_INSTR(0x06, 0x0a), + ILI9881C_COMMAND_INSTR(0x07, 0x00), + ILI9881C_COMMAND_INSTR(0x08, 0x00), + ILI9881C_COMMAND_INSTR(0x09, 0x61), + ILI9881C_COMMAND_INSTR(0x0a, 0x00), + ILI9881C_COMMAND_INSTR(0x0b, 0x00), + ILI9881C_COMMAND_INSTR(0x0c, 0x01), + ILI9881C_COMMAND_INSTR(0x0d, 0x00), + ILI9881C_COMMAND_INSTR(0x0e, 0x00), + ILI9881C_COMMAND_INSTR(0x0f, 0x61), + ILI9881C_COMMAND_INSTR(0x10, 0x61), + ILI9881C_COMMAND_INSTR(0x11, 0x00), + ILI9881C_COMMAND_INSTR(0x12, 0x00), + ILI9881C_COMMAND_INSTR(0x13, 0x00), + ILI9881C_COMMAND_INSTR(0x14, 0x00), + ILI9881C_COMMAND_INSTR(0x15, 0x00), + ILI9881C_COMMAND_INSTR(0x16, 0x00), + ILI9881C_COMMAND_INSTR(0x17, 0x00), + ILI9881C_COMMAND_INSTR(0x18, 0x00), + ILI9881C_COMMAND_INSTR(0x19, 0x00), + ILI9881C_COMMAND_INSTR(0x1a, 0x00), + ILI9881C_COMMAND_INSTR(0x1b, 0x00), + ILI9881C_COMMAND_INSTR(0x1c, 0x00), + ILI9881C_COMMAND_INSTR(0x1d, 0x00), + ILI9881C_COMMAND_INSTR(0x1e, 0x40), + ILI9881C_COMMAND_INSTR(0x1f, 0x80), + ILI9881C_COMMAND_INSTR(0x20, 0x06), + ILI9881C_COMMAND_INSTR(0x21, 0x01), + ILI9881C_COMMAND_INSTR(0x22, 0x00), + ILI9881C_COMMAND_INSTR(0x23, 0x00), + ILI9881C_COMMAND_INSTR(0x24, 0x00), + ILI9881C_COMMAND_INSTR(0x25, 0x00), + ILI9881C_COMMAND_INSTR(0x26, 0x00), + ILI9881C_COMMAND_INSTR(0x27, 0x00), + ILI9881C_COMMAND_INSTR(0x28, 0x33), + ILI9881C_COMMAND_INSTR(0x29, 0x03), + ILI9881C_COMMAND_INSTR(0x2a, 0x00), + ILI9881C_COMMAND_INSTR(0x2b, 0x00), + ILI9881C_COMMAND_INSTR(0x2c, 0x00), + ILI9881C_COMMAND_INSTR(0x2d, 0x00), + ILI9881C_COMMAND_INSTR(0x2e, 0x00), + ILI9881C_COMMAND_INSTR(0x2f, 0x00), + ILI9881C_COMMAND_INSTR(0x30, 0x00), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x32, 0x00), + ILI9881C_COMMAND_INSTR(0x33, 0x00), + ILI9881C_COMMAND_INSTR(0x34, 0x04), + ILI9881C_COMMAND_INSTR(0x35, 0x00), + ILI9881C_COMMAND_INSTR(0x36, 0x00), + ILI9881C_COMMAND_INSTR(0x37, 0x00), + ILI9881C_COMMAND_INSTR(0x38, 0x3c), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_COMMAND_INSTR(0x3a, 0x00), + ILI9881C_COMMAND_INSTR(0x3b, 0x00), + ILI9881C_COMMAND_INSTR(0x3c, 0x00), + ILI9881C_COMMAND_INSTR(0x3d, 0x00), + ILI9881C_COMMAND_INSTR(0x3e, 0x00), + ILI9881C_COMMAND_INSTR(0x3f, 0x00), + ILI9881C_COMMAND_INSTR(0x40, 0x00), + ILI9881C_COMMAND_INSTR(0x41, 0x00), + ILI9881C_COMMAND_INSTR(0x42, 0x00), + ILI9881C_COMMAND_INSTR(0x43, 0x00), + ILI9881C_COMMAND_INSTR(0x44, 0x00), + ILI9881C_COMMAND_INSTR(0x50, 0x10), + ILI9881C_COMMAND_INSTR(0x51, 0x32), + ILI9881C_COMMAND_INSTR(0x52, 0x54), + ILI9881C_COMMAND_INSTR(0x53, 0x76), + ILI9881C_COMMAND_INSTR(0x54, 0x98), + ILI9881C_COMMAND_INSTR(0x55, 0xba), + ILI9881C_COMMAND_INSTR(0x56, 0x10), + ILI9881C_COMMAND_INSTR(0x57, 0x32), + ILI9881C_COMMAND_INSTR(0x58, 0x54), + ILI9881C_COMMAND_INSTR(0x59, 0x76), + ILI9881C_COMMAND_INSTR(0x5a, 0x98), + ILI9881C_COMMAND_INSTR(0x5b, 0xba), + ILI9881C_COMMAND_INSTR(0x5c, 0xdc), + ILI9881C_COMMAND_INSTR(0x5d, 0xfe), + ILI9881C_COMMAND_INSTR(0x5e, 0x00), + ILI9881C_COMMAND_INSTR(0x5f, 0x0e), + ILI9881C_COMMAND_INSTR(0x60, 0x0f), + ILI9881C_COMMAND_INSTR(0x61, 0x0c), + ILI9881C_COMMAND_INSTR(0x62, 0x0d), + ILI9881C_COMMAND_INSTR(0x63, 0x06), + ILI9881C_COMMAND_INSTR(0x64, 0x07), + ILI9881C_COMMAND_INSTR(0x65, 0x02), + ILI9881C_COMMAND_INSTR(0x66, 0x02), + ILI9881C_COMMAND_INSTR(0x67, 0x02), + ILI9881C_COMMAND_INSTR(0x68, 0x02), + ILI9881C_COMMAND_INSTR(0x69, 0x01), + ILI9881C_COMMAND_INSTR(0x6a, 0x00), + ILI9881C_COMMAND_INSTR(0x6b, 0x02), + ILI9881C_COMMAND_INSTR(0x6c, 0x15), + ILI9881C_COMMAND_INSTR(0x6d, 0x14), + ILI9881C_COMMAND_INSTR(0x6e, 0x02), + ILI9881C_COMMAND_INSTR(0x6f, 0x02), + ILI9881C_COMMAND_INSTR(0x70, 0x02), + ILI9881C_COMMAND_INSTR(0x71, 0x02), + ILI9881C_COMMAND_INSTR(0x72, 0x02), + ILI9881C_COMMAND_INSTR(0x73, 0x02), + ILI9881C_COMMAND_INSTR(0x74, 0x02), + ILI9881C_COMMAND_INSTR(0x75, 0x0e), + ILI9881C_COMMAND_INSTR(0x76, 0x0f), + ILI9881C_COMMAND_INSTR(0x77, 0x0c), + ILI9881C_COMMAND_INSTR(0x78, 0x0d), + ILI9881C_COMMAND_INSTR(0x79, 0x06), + ILI9881C_COMMAND_INSTR(0x7a, 0x07), + ILI9881C_COMMAND_INSTR(0x7b, 0x02), + ILI9881C_COMMAND_INSTR(0x7c, 0x02), + ILI9881C_COMMAND_INSTR(0x7d, 0x02), + ILI9881C_COMMAND_INSTR(0x7e, 0x02), + ILI9881C_COMMAND_INSTR(0x7f, 0x01), + ILI9881C_COMMAND_INSTR(0x80, 0x00), + ILI9881C_COMMAND_INSTR(0x81, 0x02), + ILI9881C_COMMAND_INSTR(0x82, 0x14), + ILI9881C_COMMAND_INSTR(0x83, 0x15), + ILI9881C_COMMAND_INSTR(0x84, 0x02), + ILI9881C_COMMAND_INSTR(0x85, 0x02), + ILI9881C_COMMAND_INSTR(0x86, 0x02), + ILI9881C_COMMAND_INSTR(0x87, 0x02), + ILI9881C_COMMAND_INSTR(0x88, 0x02), + ILI9881C_COMMAND_INSTR(0x89, 0x02), + ILI9881C_COMMAND_INSTR(0x8a, 0x02), + + ILI9881C_SWITCH_PAGE_INSTR(4), + ILI9881C_COMMAND_INSTR(0x38, 0x01), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_COMMAND_INSTR(0x6c, 0x15), + ILI9881C_COMMAND_INSTR(0x6e, 0x2a), + ILI9881C_COMMAND_INSTR(0x6f, 0x33), + ILI9881C_COMMAND_INSTR(0x3a, 0x94), + ILI9881C_COMMAND_INSTR(0x8d, 0x14), + ILI9881C_COMMAND_INSTR(0x87, 0xba), + ILI9881C_COMMAND_INSTR(0x26, 0x76), + ILI9881C_COMMAND_INSTR(0xb2, 0xd1), + ILI9881C_COMMAND_INSTR(0xb5, 0x06), + ILI9881C_COMMAND_INSTR(0x3b, 0x98), + + ILI9881C_SWITCH_PAGE_INSTR(1), + ILI9881C_COMMAND_INSTR(0x22, 0x0a), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x53, 0x71), + ILI9881C_COMMAND_INSTR(0x55, 0x8f), + ILI9881C_COMMAND_INSTR(0x40, 0x33), + ILI9881C_COMMAND_INSTR(0x50, 0x96), + ILI9881C_COMMAND_INSTR(0x51, 0x96), + ILI9881C_COMMAND_INSTR(0x60, 0x23), + ILI9881C_COMMAND_INSTR(0xa0, 0x08), + ILI9881C_COMMAND_INSTR(0xa1, 0x1d), + ILI9881C_COMMAND_INSTR(0xa2, 0x2a), + ILI9881C_COMMAND_INSTR(0xa3, 0x10), + ILI9881C_COMMAND_INSTR(0xa4, 0x15), + ILI9881C_COMMAND_INSTR(0xa5, 0x28), + ILI9881C_COMMAND_INSTR(0xa6, 0x1c), + ILI9881C_COMMAND_INSTR(0xa7, 0x1d), + ILI9881C_COMMAND_INSTR(0xa8, 0x7e), + ILI9881C_COMMAND_INSTR(0xa9, 0x1d), + ILI9881C_COMMAND_INSTR(0xaa, 0x29), + ILI9881C_COMMAND_INSTR(0xab, 0x6b), + ILI9881C_COMMAND_INSTR(0xac, 0x1a), + ILI9881C_COMMAND_INSTR(0xad, 0x18), + ILI9881C_COMMAND_INSTR(0xae, 0x4b), + ILI9881C_COMMAND_INSTR(0xaf, 0x20), + ILI9881C_COMMAND_INSTR(0xb0, 0x27), + ILI9881C_COMMAND_INSTR(0xb1, 0x50), + ILI9881C_COMMAND_INSTR(0xb2, 0x64), + ILI9881C_COMMAND_INSTR(0xb3, 0x39), + ILI9881C_COMMAND_INSTR(0xc0, 0x08), + ILI9881C_COMMAND_INSTR(0xc1, 0x1d), + ILI9881C_COMMAND_INSTR(0xc2, 0x2a), + ILI9881C_COMMAND_INSTR(0xc3, 0x10), + ILI9881C_COMMAND_INSTR(0xc4, 0x15), + ILI9881C_COMMAND_INSTR(0xc5, 0x28), + ILI9881C_COMMAND_INSTR(0xc6, 0x1c), + ILI9881C_COMMAND_INSTR(0xc7, 0x1d), + ILI9881C_COMMAND_INSTR(0xc8, 0x7e), + ILI9881C_COMMAND_INSTR(0xc9, 0x1d), + ILI9881C_COMMAND_INSTR(0xca, 0x29), + ILI9881C_COMMAND_INSTR(0xcb, 0x6b), + ILI9881C_COMMAND_INSTR(0xcc, 0x1a), + ILI9881C_COMMAND_INSTR(0xcd, 0x18), + ILI9881C_COMMAND_INSTR(0xce, 0x4b), + ILI9881C_COMMAND_INSTR(0xcf, 0x20), + ILI9881C_COMMAND_INSTR(0xd0, 0x27), + ILI9881C_COMMAND_INSTR(0xd1, 0x50), + ILI9881C_COMMAND_INSTR(0xd2, 0x64), + ILI9881C_COMMAND_INSTR(0xd3, 0x39), + + ILI9881C_SWITCH_PAGE_INSTR(0), + ILI9881C_COMMAND_INSTR(0x3a, 0x77), + ILI9881C_COMMAND_INSTR(0x36, 0x00), +}; + static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel) { return container_of(panel, struct ili9881c, panel); @@ -2035,9 +2235,19 @@ static int ili9881c_prepare(struct drm_panel *panel) int ret; /* Power the panel */ + if (ctx->iovcc) { + ret = regulator_enable(ctx->iovcc); + if (ret) + return ret; + } + + msleep(5); ret = regulator_enable(ctx->power); - if (ret) - return ret; + if (ret) { + mctx.accum_err = ret; + goto disable_iovcc; + } + msleep(5); /* And reset it */ @@ -2074,6 +2284,9 @@ static int ili9881c_prepare(struct drm_panel *panel) disable_power: regulator_disable(ctx->power); +disable_iovcc: + if (ctx->iovcc) + regulator_disable(ctx->iovcc); return mctx.accum_err; } @@ -2085,6 +2298,8 @@ static int ili9881c_unprepare(struct drm_panel *panel) mipi_dsi_dcs_set_display_off_multi(&mctx); mipi_dsi_dcs_enter_sleep_mode_multi(&mctx); regulator_disable(ctx->power); + if (ctx->iovcc) + regulator_disable(ctx->iovcc); gpiod_set_value_cansleep(ctx->reset, 1); return 0; @@ -2260,6 +2475,23 @@ static const struct drm_display_mode bsd1218_a101kl68_default_mode = { .height_mm = 170, }; +static const struct drm_display_mode waveshare_7inch_a_mode = { + .clock = 83333, + + .hdisplay = 720, + .hsync_start = 720 + 120, + .hsync_end = 720 + 120 + 100, + .htotal = 720 + 120 + 100 + 100, + + .vdisplay = 1280, + .vsync_start = 1280 + 10, + .vsync_end = 1280 + 10 + 10, + .vtotal = 1280 + 10 + 10 + 10, + + .width_mm = 85, + .height_mm = 154, +}; + static int ili9881c_get_modes(struct drm_panel *panel, struct drm_connector *connector) { @@ -2329,6 +2561,11 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) return dev_err_probe(&dsi->dev, PTR_ERR(ctx->power), "Couldn't get our power regulator\n"); + ctx->iovcc = devm_regulator_get_optional(&dsi->dev, "iovcc"); + if (IS_ERR(ctx->iovcc)) + return dev_err_probe(&dsi->dev, PTR_ERR(ctx->iovcc), + "Couldn't get our iovcc regulator\n"); + ctx->reset = devm_gpiod_get_optional(&dsi->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset)) return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset), @@ -2454,6 +2691,15 @@ static const struct ili9881c_desc bsd1218_a101kl68_desc = { .lanes = 4, }; +static const struct ili9881c_desc waveshare_7inch_a_desc = { + .init = waveshare_7inch_a_init, + .init_length = ARRAY_SIZE(waveshare_7inch_a_init), + .mode = &waveshare_7inch_a_mode, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_HSE | + MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS, + .lanes = 2, +}; + static const struct of_device_id ili9881c_of_match[] = { { .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc }, { .compatible = "bestar,bsd1218-a101kl68", .data = &bsd1218_a101kl68_desc }, @@ -2462,6 +2708,7 @@ static const struct of_device_id ili9881c_of_match[] = { { .compatible = "tdo,tl050hdv35", .data = &tl050hdv35_desc }, { .compatible = "wanchanglong,w552946aaa", .data = &w552946aaa_desc }, { .compatible = "wanchanglong,w552946aba", .data = &w552946aba_desc }, + { .compatible = "waveshare,7.0-dsi-touch-a", .data = &waveshare_7inch_a_desc }, { .compatible = "ampire,am8001280g", .data = &am8001280g_desc }, { .compatible = "raspberrypi,dsi-5inch", &rpi_5inch_desc }, { .compatible = "raspberrypi,dsi-7inch", &rpi_7inch_desc }, diff --git a/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c b/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c index 7157b1299bfd..f6b04de1182e 100644 --- a/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c +++ b/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c @@ -2955,9 +2955,11 @@ static int jadard_dsi_probe(struct mipi_dsi_device *dsi) dsi->format = desc->format; dsi->lanes = desc->lanes; if (!dsi->lanes) { - dsi->lanes = drm_of_get_data_lanes_count_remote(dsi->dev.of_node, 0, -1, 2, 4); - if (dsi->lanes < 0) - return dsi->lanes; + ret = drm_of_get_data_lanes_count_remote(dsi->dev.of_node, 0, -1, 2, 4); + if (ret < 0) + return ret; + dsi->lanes = ret; + if (dsi->lanes == 4) { if (!desc->mode_4ln) { dev_err(&dsi->dev, "4-lane config is not supported\n"); diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35532.c b/drivers/gpu/drm/panel/panel-novatek-nt35532.c new file mode 100644 index 000000000000..184f61bca7ca --- /dev/null +++ b/drivers/gpu/drm/panel/panel-novatek-nt35532.c @@ -0,0 +1,796 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree. + * Copyright (c) 2026 Cristian Cozzolino <cristian_ci@protonmail.com> + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_probe_helper.h> + +struct novatek_nt35532 { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct regulator_bulk_data *supplies; + struct gpio_desc *reset_gpio; + const struct nt35532_panel_desc *desc; +}; + +struct nt35532_panel_desc { + const struct drm_display_mode *mode; + int (*on)(struct novatek_nt35532 *ctx); +}; + +static const struct regulator_bulk_data nt35532_supplies[] = { + { .supply = "vci" }, + { .supply = "vddi" }, + { .supply = "avee" }, + { .supply = "avdd" }, +}; + +static inline struct novatek_nt35532 *to_novatek_nt35532(struct drm_panel *panel) +{ + return container_of_const(panel, struct novatek_nt35532, panel); +} + +static void nt35532_reset(struct novatek_nt35532 *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(5000, 6000); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); +} + +static int rimob_panel_on(struct novatek_nt35532 *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6e, 0x80); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x68, 0x13); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x05); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0x31); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0x7e); + + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x01, 0x55); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x04, 0x0c); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x05, 0x3a); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x06, 0x50); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x07, 0xd0); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0a, 0x0f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0c, 0x06); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0d, 0x6b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0e, 0x6b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0f, 0x70); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x10, 0x63); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x11, 0x3c); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x12, 0x5c); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x15, 0x60); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x16, 0x15); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x17, 0x15); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5b, 0xca); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5c, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5d, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5f, 0x1b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x60, 0xd5); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x61, 0xf0); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6c, 0xab); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6d, 0x44); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6e, 0x80); + + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x05); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x00, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x01, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x02, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x03, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x04, 0x38); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x05, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x06, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x07, 0x19); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x08, 0x1b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x09, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0a, 0x1d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0b, 0x17); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0c, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0d, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0e, 0x08); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0f, 0x0c); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x10, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x11, 0x10); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x12, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x13, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x14, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x15, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x16, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x17, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x18, 0x38); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x19, 0x18); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1a, 0x1a); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1b, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1c, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1d, 0x1c); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1e, 0x16); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1f, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x20, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x21, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x22, 0x06); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x23, 0x0a); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x24, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x25, 0x0e); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x26, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x27, 0x3f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x54, 0x08); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x55, 0x07); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x56, 0x1a); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x58, 0x19); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x59, 0x36); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5a, 0x1b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5b, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5c, 0x32); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5e, 0x27); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5f, 0x28); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x60, 0x2b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x61, 0x2c); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x62, 0x18); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x63, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x64, 0x32); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x65, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x66, 0x44); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x67, 0x11); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x68, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x69, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6a, 0x06); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6b, 0x22); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6c, 0x08); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6d, 0x08); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x78, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x79, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7e, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7f, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x80, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x81, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8d, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8e, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xc0); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x90, 0x73); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x91, 0x10); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x92, 0x09); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x96, 0x11); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x97, 0x14); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x98, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x99, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9a, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9b, 0x61); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9c, 0x15); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9d, 0x30); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9f, 0x0f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa2, 0xb0); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa7, 0x0a); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaa, 0x70); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xab, 0xda); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xac, 0xff); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xae, 0xf4); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaf, 0x40); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0x7f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1, 0x16); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb2, 0x53); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb3, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb4, 0x2a); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb5, 0x3a); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb6, 0xf0); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbc, 0x85); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbd, 0xf8); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbe, 0x3b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbf, 0x13); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x77); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x77); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0x77); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x77); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x77); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x77); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x77); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x77); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0xaa); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0x2a); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0xaa); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x92); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x18); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x88); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0xaa); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xef, 0x70); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0x03); + + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x75, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x76, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x77, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x78, 0x20); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x79, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7a, 0x49); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7b, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7c, 0x66); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7d, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7e, 0x7d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7f, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x80, 0x91); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x81, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x82, 0xa3); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0xb3); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x85, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x86, 0xc1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x87, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x88, 0xf1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x89, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8a, 0x18); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8b, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8c, 0x54); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8d, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8e, 0x85); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x90, 0xd1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x91, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x92, 0x0c); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x93, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x94, 0x0e); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x95, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x96, 0x43); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x97, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x98, 0x7d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x99, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9a, 0xa2); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9b, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9c, 0xd7); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9d, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9e, 0xf8); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9f, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa0, 0x2b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa2, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa3, 0x3a); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa4, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa5, 0x4b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa6, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa7, 0x5d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaa, 0x73); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xab, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xac, 0x8e); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xad, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xae, 0xae); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaf, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0xc9); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb2, 0xcd); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb3, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb4, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb5, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb6, 0x20); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb7, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb8, 0x49); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb9, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xba, 0x66); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbb, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbc, 0x7d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbd, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbe, 0x91); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbf, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0xa3); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0xb3); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0xc1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0xf1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x18); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0x54); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x85); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0xd1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x0c); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x0e); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x43); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0x7d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0xa2); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xda, 0xd7); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdb, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdc, 0xf8); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdd, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xde, 0x2b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdf, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe0, 0x3a); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe1, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe2, 0x4b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe3, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe4, 0x5d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0x73); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0x8e); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0xae); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xeb, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xec, 0xc9); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0xcd); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xef, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf1, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf2, 0x20); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf3, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf4, 0x49); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf5, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf6, 0x66); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf8, 0x7d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0x91); + + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x00, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x01, 0xa3); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x02, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x03, 0xb3); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x04, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x05, 0xc1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x06, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x07, 0xf1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x08, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x09, 0x18); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0a, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0b, 0x54); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0c, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0d, 0x85); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0e, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0f, 0xd1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x10, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x11, 0x0c); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x12, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x13, 0x0e); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x14, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x15, 0x43); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x16, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x17, 0x7d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x18, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x19, 0xa2); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1a, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1b, 0xd7); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1c, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1d, 0xf8); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1e, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1f, 0x2b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x20, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x21, 0x3a); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x22, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x23, 0x4b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x24, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x25, 0x5d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x26, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x27, 0x73); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x28, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x29, 0x8e); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x2a, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x2b, 0xae); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x2d, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x2f, 0xc9); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x30, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x31, 0xcd); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x32, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x33, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x34, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x35, 0x20); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x36, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x37, 0x49); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x38, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x39, 0x66); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x3a, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x3b, 0x7d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x3d, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x3f, 0x91); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x40, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x41, 0xa3); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x42, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x43, 0xb3); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x44, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x45, 0xc1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x46, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x47, 0xf1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x48, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x49, 0x18); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x4a, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x4b, 0x54); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x4c, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x4d, 0x85); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x4e, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x4f, 0xd1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x50, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x51, 0x0c); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x52, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x53, 0x0e); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x54, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x55, 0x43); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x56, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x58, 0x7d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x59, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5a, 0xa2); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5b, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5c, 0xd7); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5d, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5e, 0xf8); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5f, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x60, 0x2b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x61, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x62, 0x3a); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x63, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x64, 0x4b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x65, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x66, 0x5d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x67, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x68, 0x73); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x69, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6a, 0x8e); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6b, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6c, 0xae); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6d, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6e, 0xc9); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6f, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x70, 0xcd); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x71, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x72, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x73, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x74, 0x20); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x75, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x76, 0x49); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x77, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x78, 0x66); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x79, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7a, 0x7d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7b, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7c, 0x91); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7d, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7e, 0xa3); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7f, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x80, 0xb3); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x81, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x82, 0xc1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0xf1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x85, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x86, 0x18); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x87, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x88, 0x54); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x89, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8a, 0x85); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8b, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8c, 0xd1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8d, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8e, 0x0c); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x90, 0x0e); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x91, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x92, 0x43); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x93, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x94, 0x7d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x95, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x96, 0xa2); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x97, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x98, 0xd7); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x99, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9a, 0xf8); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9b, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9c, 0x2b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9d, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9e, 0x3a); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9f, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa0, 0x4b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa2, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa3, 0x5d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa4, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa5, 0x73); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa6, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa7, 0x8e); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaa, 0xae); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xab, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xac, 0xc9); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xad, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xae, 0xcd); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaf, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb2, 0x20); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb3, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb4, 0x49); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb5, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb6, 0x66); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb7, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb8, 0x7d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb9, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xba, 0x91); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbb, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbc, 0xa3); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbd, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbe, 0xb3); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbf, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0xc1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0xf1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x18); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x54); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x85); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0xd1); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x0c); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x0e); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x43); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x7d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0xa2); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0xd7); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0x02); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0xf8); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xda, 0x2b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdb, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdc, 0x3a); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdd, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xde, 0x4b); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdf, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe0, 0x5d); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe1, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe2, 0x73); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe3, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe4, 0x8e); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0xae); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0xc9); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0xcd); + + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0xee); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x02, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x40, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x02, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x41, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x02, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x42, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xba, 0x03); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x35, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x36, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x10); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x0f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0x0f); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0x48); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0x00); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, MIPI_DCS_EXIT_SLEEP_MODE, 0x00); + mipi_dsi_msleep(&dsi_ctx, 120); + mipi_dsi_generic_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_DISPLAY_ON, 0x00); + mipi_dsi_msleep(&dsi_ctx, 50); + + return dsi_ctx.accum_err; +} + +static int nt35532_off(struct novatek_nt35532 *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 50); + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 120); + + return dsi_ctx.accum_err; +} + +static int nt35532_prepare(struct drm_panel *panel) +{ + struct novatek_nt35532 *ctx = to_novatek_nt35532(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(nt35532_supplies), ctx->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + nt35532_reset(ctx); + + ret = ctx->desc->on(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(nt35532_supplies), ctx->supplies); + return ret; + } + + return 0; +} + +static int nt35532_unprepare(struct drm_panel *panel) +{ + struct novatek_nt35532 *ctx = to_novatek_nt35532(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = nt35532_off(ctx); + if (ret < 0) + dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(nt35532_supplies), ctx->supplies); + + return 0; +} + +static const struct drm_display_mode rimob_panel_mode = { + .clock = (1080 + 100 + 6 + 94) * (1920 + 15 + 6 + 10) * 60 / 1000, + .hdisplay = 1080, + .hsync_start = 1080 + 100, + .hsync_end = 1080 + 100 + 6, + .htotal = 1080 + 100 + 6 + 94, + .vdisplay = 1920, + .vsync_start = 1920 + 15, + .vsync_end = 1920 + 15 + 6, + .vtotal = 1920 + 15 + 6 + 10, + .width_mm = 68, + .height_mm = 121, + .type = DRM_MODE_TYPE_DRIVER, +}; + +static int nt35532_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct novatek_nt35532 *ctx = to_novatek_nt35532(panel); + const struct drm_display_mode *mode = ctx->desc->mode; + + return drm_connector_helper_get_modes_fixed(connector, mode); +} + +static const struct nt35532_panel_desc rimob_panel_desc = { + .mode = &rimob_panel_mode, + .on = rimob_panel_on, +}; + +static const struct drm_panel_funcs novatek_nt35532_panel_funcs = { + .prepare = nt35532_prepare, + .unprepare = nt35532_unprepare, + .get_modes = nt35532_get_modes, +}; + +static int nt35532_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct novatek_nt35532 *ctx; + int ret; + + ctx = devm_drm_panel_alloc(dev, struct novatek_nt35532, panel, + &novatek_nt35532_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ctx->desc = device_get_match_data(dev); + + ret = devm_regulator_bulk_get_const(dev, + ARRAY_SIZE(nt35532_supplies), + nt35532_supplies, + &ctx->supplies); + if (ret < 0) + return ret; + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), + "Failed to get reset-gpios\n"); + + ctx->dsi = dsi; + mipi_dsi_set_drvdata(dsi, ctx); + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_LPM; + + ctx->panel.prepare_prev_first = true; + + ret = drm_panel_of_backlight(&ctx->panel); + if (ret) + return dev_err_probe(dev, ret, "Failed to get backlight\n"); + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + drm_panel_remove(&ctx->panel); + return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); + } + + return 0; +} + +static void nt35532_remove(struct mipi_dsi_device *dsi) +{ + struct novatek_nt35532 *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + + ret = mipi_dsi_detach(dsi); + if (ret < 0) + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); + + drm_panel_remove(&ctx->panel); +} + +static const struct of_device_id nt35532_of_match[] = { + { .compatible = "flipkart,rimob-panel-nt35532-cs", .data = &rimob_panel_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, nt35532_of_match); + +static struct mipi_dsi_driver nt35532_driver = { + .probe = nt35532_probe, + .remove = nt35532_remove, + .driver = { + .name = "panel-novatek-nt35532", + .of_match_table = nt35532_of_match, + }, +}; +module_mipi_dsi_driver(nt35532_driver); + +MODULE_DESCRIPTION("DRM driver for Novatek NT35532-based 1080p video mode DSI panel"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c index 3c3308fc55df..d21d93a0700e 100644 --- a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c +++ b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c @@ -44,14 +44,23 @@ static inline struct wuxga_nt_panel *to_wuxga_nt_panel(struct drm_panel *panel) static int wuxga_nt_panel_on(struct wuxga_nt_panel *wuxga_nt) { - return mipi_dsi_turn_on_peripheral(wuxga_nt->dsi); + struct mipi_dsi_multi_context dsi_ctx = { + .dsi = wuxga_nt->dsi + }; + + mipi_dsi_turn_on_peripheral_multi(&dsi_ctx); + return dsi_ctx.accum_err; } static int wuxga_nt_panel_disable(struct drm_panel *panel) { struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel); + struct mipi_dsi_multi_context dsi_ctx = { + .dsi = wuxga_nt->dsi + }; - return mipi_dsi_shutdown_peripheral(wuxga_nt->dsi); + mipi_dsi_shutdown_peripheral_multi(&dsi_ctx); + return dsi_ctx.accum_err; } static int wuxga_nt_panel_unprepare(struct drm_panel *panel) @@ -94,15 +103,8 @@ static int wuxga_nt_panel_prepare(struct drm_panel *panel) msleep(250); ret = wuxga_nt_panel_on(wuxga_nt); - if (ret < 0) { - dev_err(panel->dev, "failed to set panel on: %d\n", ret); - goto poweroff; - } - - return 0; - -poweroff: - regulator_disable(wuxga_nt->supply); + if (ret < 0) + regulator_disable(wuxga_nt->supply); return ret; } diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index b2708a1fe464..2fbb9dff0a34 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1902,6 +1902,39 @@ static const struct panel_desc dataimage_scf0700c48ggu18 = { .connector_type = DRM_MODE_CONNECTOR_DPI, }; +static const struct display_timing displaytech_dt050btft_pts_timing = { + /* The TYP pixel clock are recalculated from tV * tH * 60 Hz */ + .pixelclock = { 30000000, 33264000, 50000000 }, + .hactive = { 800, 800, 800 }, + .hfront_porch = { 16, 210, 354 }, + /* Datasheet Figure 3 indicates, that tHPW is part of tHBP */ + .hback_porch = { 41, 26, 6 }, + .hsync_len = { 1, 20, 40 }, + .vactive = { 480, 480, 480 }, + .vfront_porch = { 7, 22, 147 }, + /* Datasheet Figure 2 indicates, that tVPW is part of tVBP */ + .vback_porch = { 22, 13, 3 }, + .vsync_len = { 1, 10, 20 }, + .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW | + DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE | + DISPLAY_FLAGS_SYNC_POSEDGE, +}; + +static const struct panel_desc displaytech_dt050btft_pts = { + .timings = &displaytech_dt050btft_pts_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 108, + .height = 65, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE | + DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE, + .connector_type = DRM_MODE_CONNECTOR_DPI, +}; + static const struct display_timing dlc_dlc0700yzg_1_timing = { .pixelclock = { 45000000, 51200000, 57000000 }, .hactive = { 1024, 1024, 1024 }, @@ -4603,6 +4636,32 @@ static const struct panel_desc starry_kr070pe2t = { .connector_type = DRM_MODE_CONNECTOR_DPI, }; +static const struct display_timing startek_kd070hdfld092_timing = { + .pixelclock = { 40800000, 51200000, 67200000 }, + .hactive = { 1024, 1024, 1024 }, + .hfront_porch = { 40, 160, 216 }, + .hback_porch = { 30, 140, 140 }, + .hsync_len = { 20, 20, 20 }, + .vactive = { 600, 600, 600 }, + .vfront_porch = { 2, 12, 177 }, + .vback_porch = { 5, 20, 20 }, + .vsync_len = { 3, 3, 3 }, + .flags = DISPLAY_FLAGS_DE_HIGH, +}; + +static const struct panel_desc startek_kd070hdfld092 = { + .timings = &startek_kd070hdfld092_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 154, + .height = 86, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct display_timing startek_kd070wvfpa_mode = { .pixelclock = { 25200000, 27200000, 30500000 }, .hactive = { 800, 800, 800 }, @@ -5656,6 +5715,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "dataimage,scf0700c48ggu18", .data = &dataimage_scf0700c48ggu18, }, { + .compatible = "displaytech,dt050btft-pts", + .data = &displaytech_dt050btft_pts, + }, { .compatible = "dlc,dlc0700yzg-1", .data = &dlc_dlc0700yzg_1, }, { @@ -5965,6 +6027,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "starry,kr070pe2t", .data = &starry_kr070pe2t, }, { + .compatible = "startek,kd070hdfld092", + .data = &startek_kd070hdfld092, + }, { .compatible = "startek,kd070wvfpa", .data = &startek_kd070wvfpa, }, { @@ -6317,6 +6382,39 @@ static const struct panel_desc_dsi osd101t2045_53ts = { .lanes = 4, }; +static const struct drm_display_mode tsd_tst070wsbe_196c_mode = { + .clock = 52477, + .hdisplay = 1024, + .hsync_start = 1024 + 160, + .hsync_end = 1024 + 160 + 12, + .htotal = 1024 + 160 + 160 + 12, + .vdisplay = 600, + .vsync_start = 600 + 12, + .vsync_end = 600 + 12 + 10, + .vtotal = 600 + 12 + 10 + 23, +}; + +static const struct panel_desc_dsi tsd_tst070wsbe_196c = { + .desc = { + .modes = &tsd_tst070wsbe_196c_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 190, + .height = 121, + }, + .delay = { + .prepare = 20, + }, + .connector_type = DRM_MODE_CONNECTOR_DSI, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM | + MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_VIDEO_SYNC_PULSE, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, +}; + static const struct of_device_id dsi_of_match[] = { { .compatible = "auo,b080uan01", @@ -6337,6 +6435,9 @@ static const struct of_device_id dsi_of_match[] = { .compatible = "osddisplays,osd101t2045-53ts", .data = &osd101t2045_53ts }, { + .compatible = "team-source-display,tst070wsbe-196c", + .data = &tsd_tst070wsbe_196c + }, { /* sentinel */ } }; diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c index bc62a498a8a8..bd417d6ae8c0 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -19,40 +19,14 @@ #include "panthor_devfreq.h" #include "panthor_device.h" #include "panthor_fw.h" +#include "panthor_fw_regs.h" #include "panthor_gem.h" #include "panthor_gpu.h" #include "panthor_hw.h" #include "panthor_mmu.h" #include "panthor_pwr.h" -#include "panthor_regs.h" #include "panthor_sched.h" -static int panthor_gpu_coherency_init(struct panthor_device *ptdev) -{ - BUILD_BUG_ON(GPU_COHERENCY_NONE != DRM_PANTHOR_GPU_COHERENCY_NONE); - BUILD_BUG_ON(GPU_COHERENCY_ACE_LITE != DRM_PANTHOR_GPU_COHERENCY_ACE_LITE); - BUILD_BUG_ON(GPU_COHERENCY_ACE != DRM_PANTHOR_GPU_COHERENCY_ACE); - - /* Start with no coherency, and update it if the device is flagged coherent. */ - ptdev->gpu_info.selected_coherency = GPU_COHERENCY_NONE; - ptdev->coherent = device_get_dma_attr(ptdev->base.dev) == DEV_DMA_COHERENT; - - if (!ptdev->coherent) - return 0; - - /* Check if the ACE-Lite coherency protocol is actually supported by the GPU. - * ACE protocol has never been supported for command stream frontend GPUs. - */ - if ((gpu_read(ptdev, GPU_COHERENCY_FEATURES) & - GPU_COHERENCY_PROT_BIT(ACE_LITE))) { - ptdev->gpu_info.selected_coherency = GPU_COHERENCY_ACE_LITE; - return 0; - } - - drm_err(&ptdev->base, "Coherency not supported by the device"); - return -ENOTSUPP; -} - static int panthor_clk_init(struct panthor_device *ptdev) { ptdev->clks.core = devm_clk_get(ptdev->base.dev, NULL); diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h index 5cba272f9b4d..4e4607bca7cc 100644 --- a/drivers/gpu/drm/panthor/panthor_device.h +++ b/drivers/gpu/drm/panthor/panthor_device.h @@ -82,6 +82,9 @@ struct panthor_irq { /** @ptdev: Panthor device */ struct panthor_device *ptdev; + /** @iomem: CPU mapping of IRQ base address */ + void __iomem *iomem; + /** @irq: IRQ number. */ int irq; @@ -488,6 +491,11 @@ panthor_exception_is_fault(u32 exception_code) const char *panthor_exception_name(struct panthor_device *ptdev, u32 exception_code); +#define INT_RAWSTAT 0x0 +#define INT_CLEAR 0x4 +#define INT_MASK 0x8 +#define INT_STAT 0xc + /** * PANTHOR_IRQ_HANDLER() - Define interrupt handlers and the interrupt * registration function. @@ -498,14 +506,13 @@ const char *panthor_exception_name(struct panthor_device *ptdev, * * void (*handler)(struct panthor_device *, u32 status); */ -#define PANTHOR_IRQ_HANDLER(__name, __reg_prefix, __handler) \ +#define PANTHOR_IRQ_HANDLER(__name, __handler) \ static irqreturn_t panthor_ ## __name ## _irq_raw_handler(int irq, void *data) \ { \ struct panthor_irq *pirq = data; \ - struct panthor_device *ptdev = pirq->ptdev; \ enum panthor_irq_state old_state; \ \ - if (!gpu_read(ptdev, __reg_prefix ## _INT_STAT)) \ + if (!gpu_read(pirq->iomem, INT_STAT)) \ return IRQ_NONE; \ \ guard(spinlock_irqsave)(&pirq->mask_lock); \ @@ -515,7 +522,7 @@ static irqreturn_t panthor_ ## __name ## _irq_raw_handler(int irq, void *data) if (old_state != PANTHOR_IRQ_STATE_ACTIVE) \ return IRQ_NONE; \ \ - gpu_write(ptdev, __reg_prefix ## _INT_MASK, 0); \ + gpu_write(pirq->iomem, INT_MASK, 0); \ return IRQ_WAKE_THREAD; \ } \ \ @@ -534,7 +541,7 @@ static irqreturn_t panthor_ ## __name ## _irq_threaded_handler(int irq, void *da * right before the HW event kicks in. TLDR; it's all expected races we're \ * covered for. \ */ \ - u32 status = gpu_read(ptdev, __reg_prefix ## _INT_RAWSTAT) & pirq->mask; \ + u32 status = gpu_read(pirq->iomem, INT_RAWSTAT) & pirq->mask; \ \ if (!status) \ break; \ @@ -550,7 +557,7 @@ static irqreturn_t panthor_ ## __name ## _irq_threaded_handler(int irq, void *da PANTHOR_IRQ_STATE_PROCESSING, \ PANTHOR_IRQ_STATE_ACTIVE); \ if (old_state == PANTHOR_IRQ_STATE_PROCESSING) \ - gpu_write(ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \ + gpu_write(pirq->iomem, INT_MASK, pirq->mask); \ } \ \ return ret; \ @@ -560,7 +567,7 @@ static inline void panthor_ ## __name ## _irq_suspend(struct panthor_irq *pirq) { \ scoped_guard(spinlock_irqsave, &pirq->mask_lock) { \ atomic_set(&pirq->state, PANTHOR_IRQ_STATE_SUSPENDING); \ - gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, 0); \ + gpu_write(pirq->iomem, INT_MASK, 0); \ } \ synchronize_irq(pirq->irq); \ atomic_set(&pirq->state, PANTHOR_IRQ_STATE_SUSPENDED); \ @@ -571,17 +578,18 @@ static inline void panthor_ ## __name ## _irq_resume(struct panthor_irq *pirq) guard(spinlock_irqsave)(&pirq->mask_lock); \ \ atomic_set(&pirq->state, PANTHOR_IRQ_STATE_ACTIVE); \ - gpu_write(pirq->ptdev, __reg_prefix ## _INT_CLEAR, pirq->mask); \ - gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \ + gpu_write(pirq->iomem, INT_CLEAR, pirq->mask); \ + gpu_write(pirq->iomem, INT_MASK, pirq->mask); \ } \ \ static int panthor_request_ ## __name ## _irq(struct panthor_device *ptdev, \ struct panthor_irq *pirq, \ - int irq, u32 mask) \ + int irq, u32 mask, void __iomem *iomem) \ { \ pirq->ptdev = ptdev; \ pirq->irq = irq; \ pirq->mask = mask; \ + pirq->iomem = iomem; \ spin_lock_init(&pirq->mask_lock); \ panthor_ ## __name ## _irq_resume(pirq); \ \ @@ -603,7 +611,7 @@ static inline void panthor_ ## __name ## _irq_enable_events(struct panthor_irq * * If the IRQ is suspended/suspending, the mask is restored at resume time. \ */ \ if (atomic_read(&pirq->state) == PANTHOR_IRQ_STATE_ACTIVE) \ - gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \ + gpu_write(pirq->iomem, INT_MASK, pirq->mask); \ } \ \ static inline void panthor_ ## __name ## _irq_disable_events(struct panthor_irq *pirq, u32 mask)\ @@ -617,80 +625,80 @@ static inline void panthor_ ## __name ## _irq_disable_events(struct panthor_irq * If the IRQ is suspended/suspending, the mask is restored at resume time. \ */ \ if (atomic_read(&pirq->state) == PANTHOR_IRQ_STATE_ACTIVE) \ - gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \ + gpu_write(pirq->iomem, INT_MASK, pirq->mask); \ } extern struct workqueue_struct *panthor_cleanup_wq; -static inline void gpu_write(struct panthor_device *ptdev, u32 reg, u32 data) +static inline void gpu_write(void __iomem *iomem, u32 reg, u32 data) { - writel(data, ptdev->iomem + reg); + writel(data, iomem + reg); } -static inline u32 gpu_read(struct panthor_device *ptdev, u32 reg) +static inline u32 gpu_read(void __iomem *iomem, u32 reg) { - return readl(ptdev->iomem + reg); + return readl(iomem + reg); } -static inline u32 gpu_read_relaxed(struct panthor_device *ptdev, u32 reg) +static inline u32 gpu_read_relaxed(void __iomem *iomem, u32 reg) { - return readl_relaxed(ptdev->iomem + reg); + return readl_relaxed(iomem + reg); } -static inline void gpu_write64(struct panthor_device *ptdev, u32 reg, u64 data) +static inline void gpu_write64(void __iomem *iomem, u32 reg, u64 data) { - gpu_write(ptdev, reg, lower_32_bits(data)); - gpu_write(ptdev, reg + 4, upper_32_bits(data)); + gpu_write(iomem, reg, lower_32_bits(data)); + gpu_write(iomem, reg + 4, upper_32_bits(data)); } -static inline u64 gpu_read64(struct panthor_device *ptdev, u32 reg) +static inline u64 gpu_read64(void __iomem *iomem, u32 reg) { - return (gpu_read(ptdev, reg) | ((u64)gpu_read(ptdev, reg + 4) << 32)); + return (gpu_read(iomem, reg) | ((u64)gpu_read(iomem, reg + 4) << 32)); } -static inline u64 gpu_read64_relaxed(struct panthor_device *ptdev, u32 reg) +static inline u64 gpu_read64_relaxed(void __iomem *iomem, u32 reg) { - return (gpu_read_relaxed(ptdev, reg) | - ((u64)gpu_read_relaxed(ptdev, reg + 4) << 32)); + return (gpu_read_relaxed(iomem, reg) | + ((u64)gpu_read_relaxed(iomem, reg + 4) << 32)); } -static inline u64 gpu_read64_counter(struct panthor_device *ptdev, u32 reg) +static inline u64 gpu_read64_counter(void __iomem *iomem, u32 reg) { u32 lo, hi1, hi2; do { - hi1 = gpu_read(ptdev, reg + 4); - lo = gpu_read(ptdev, reg); - hi2 = gpu_read(ptdev, reg + 4); + hi1 = gpu_read(iomem, reg + 4); + lo = gpu_read(iomem, reg); + hi2 = gpu_read(iomem, reg + 4); } while (hi1 != hi2); return lo | ((u64)hi2 << 32); } -#define gpu_read_poll_timeout(dev, reg, val, cond, delay_us, timeout_us) \ +#define gpu_read_poll_timeout(iomem, reg, val, cond, delay_us, timeout_us) \ read_poll_timeout(gpu_read, val, cond, delay_us, timeout_us, false, \ - dev, reg) + iomem, reg) -#define gpu_read_poll_timeout_atomic(dev, reg, val, cond, delay_us, \ +#define gpu_read_poll_timeout_atomic(iomem, reg, val, cond, delay_us, \ timeout_us) \ read_poll_timeout_atomic(gpu_read, val, cond, delay_us, timeout_us, \ - false, dev, reg) + false, iomem, reg) -#define gpu_read64_poll_timeout(dev, reg, val, cond, delay_us, timeout_us) \ +#define gpu_read64_poll_timeout(iomem, reg, val, cond, delay_us, timeout_us) \ read_poll_timeout(gpu_read64, val, cond, delay_us, timeout_us, false, \ - dev, reg) + iomem, reg) -#define gpu_read64_poll_timeout_atomic(dev, reg, val, cond, delay_us, \ +#define gpu_read64_poll_timeout_atomic(iomem, reg, val, cond, delay_us, \ timeout_us) \ read_poll_timeout_atomic(gpu_read64, val, cond, delay_us, timeout_us, \ - false, dev, reg) + false, iomem, reg) -#define gpu_read_relaxed_poll_timeout_atomic(dev, reg, val, cond, delay_us, \ +#define gpu_read_relaxed_poll_timeout_atomic(iomem, reg, val, cond, delay_us, \ timeout_us) \ read_poll_timeout_atomic(gpu_read_relaxed, val, cond, delay_us, \ - timeout_us, false, dev, reg) + timeout_us, false, iomem, reg) -#define gpu_read64_relaxed_poll_timeout(dev, reg, val, cond, delay_us, \ +#define gpu_read64_relaxed_poll_timeout(iomem, reg, val, cond, delay_us, \ timeout_us) \ read_poll_timeout(gpu_read64_relaxed, val, cond, delay_us, timeout_us, \ - false, dev, reg) + false, iomem, reg) #endif diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c index 73fc983dc9b4..e8dc4096c1d2 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -31,12 +31,12 @@ #include "panthor_devfreq.h" #include "panthor_device.h" +#include "panthor_drv.h" #include "panthor_fw.h" #include "panthor_gem.h" #include "panthor_gpu.h" #include "panthor_heap.h" #include "panthor_mmu.h" -#include "panthor_regs.h" #include "panthor_sched.h" /** @@ -839,7 +839,7 @@ static int panthor_query_timestamp_info(struct panthor_device *ptdev, } if (flags & DRM_PANTHOR_TIMESTAMP_GPU_OFFSET) - arg->timestamp_offset = gpu_read64(ptdev, GPU_TIMESTAMP_OFFSET); + arg->timestamp_offset = panthor_gpu_get_timestamp_offset(ptdev); else arg->timestamp_offset = 0; @@ -854,7 +854,7 @@ static int panthor_query_timestamp_info(struct panthor_device *ptdev, query_start_time = 0; if (flags & DRM_PANTHOR_TIMESTAMP_GPU) - arg->current_timestamp = gpu_read64_counter(ptdev, GPU_TIMESTAMP); + arg->current_timestamp = panthor_gpu_get_timestamp(ptdev); else arg->current_timestamp = 0; @@ -870,7 +870,7 @@ static int panthor_query_timestamp_info(struct panthor_device *ptdev, } if (flags & DRM_PANTHOR_TIMESTAMP_GPU_CYCLE_COUNT) - arg->cycle_count = gpu_read64_counter(ptdev, GPU_CYCLE_COUNT); + arg->cycle_count = panthor_gpu_get_cycle_count(ptdev); else arg->cycle_count = 0; diff --git a/drivers/gpu/drm/panthor/panthor_drv.h b/drivers/gpu/drm/panthor/panthor_drv.h index 1bc7ddbad23e..b81f21ed5398 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.h +++ b/drivers/gpu/drm/panthor/panthor_drv.h @@ -4,6 +4,8 @@ #ifndef __PANTHOR_DRV_H__ #define __PANTHOR_DRV_H__ +#include <linux/types.h> + extern bool panthor_transparent_hugepage; #endif diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c index be0da5b1f3ab..986151681b24 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -20,11 +20,11 @@ #include "panthor_device.h" #include "panthor_fw.h" +#include "panthor_fw_regs.h" #include "panthor_gem.h" #include "panthor_gpu.h" #include "panthor_hw.h" #include "panthor_mmu.h" -#include "panthor_regs.h" #include "panthor_sched.h" #include "panthor_trace.h" @@ -234,6 +234,9 @@ struct panthor_fw_iface { * struct panthor_fw - Firmware management */ struct panthor_fw { + /** @iomem: CPU mapping of MCU_CONTROL iomem region */ + void __iomem *iomem; + /** @vm: MCU VM. */ struct panthor_vm *vm; @@ -1054,7 +1057,7 @@ static void panthor_fw_init_global_iface(struct panthor_device *ptdev) GLB_CFG_POWEROFF_TIMER | GLB_CFG_PROGRESS_TIMER); - gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); + panthor_fw_ring_doorbell(ptdev, CSF_GLB_DOORBELL_ID); /* Kick the watchdog. */ mod_delayed_work(ptdev->reset.wq, &ptdev->fw->watchdog.ping_work, @@ -1069,7 +1072,7 @@ static void panthor_job_irq_handler(struct panthor_device *ptdev, u32 status) if (tracepoint_enabled(gpu_job_irq)) start = ktime_get_ns(); - gpu_write(ptdev, JOB_INT_CLEAR, status); + gpu_write(ptdev->fw->irq.iomem, INT_CLEAR, status); if (!ptdev->fw->booted && (status & JOB_INT_GLOBAL_IF)) ptdev->fw->booted = true; @@ -1088,22 +1091,23 @@ static void panthor_job_irq_handler(struct panthor_device *ptdev, u32 status) trace_gpu_job_irq(ptdev->base.dev, status, duration); } } -PANTHOR_IRQ_HANDLER(job, JOB, panthor_job_irq_handler); +PANTHOR_IRQ_HANDLER(job, panthor_job_irq_handler); static int panthor_fw_start(struct panthor_device *ptdev) { + struct panthor_fw *fw = ptdev->fw; bool timedout = false; ptdev->fw->booted = false; panthor_job_irq_enable_events(&ptdev->fw->irq, ~0); panthor_job_irq_resume(&ptdev->fw->irq); - gpu_write(ptdev, MCU_CONTROL, MCU_CONTROL_AUTO); + gpu_write(fw->iomem, MCU_CONTROL, MCU_CONTROL_AUTO); if (!wait_event_timeout(ptdev->fw->req_waitqueue, ptdev->fw->booted, msecs_to_jiffies(1000))) { if (!ptdev->fw->booted && - !(gpu_read(ptdev, JOB_INT_STAT) & JOB_INT_GLOBAL_IF)) + !(gpu_read(fw->irq.iomem, INT_STAT) & JOB_INT_GLOBAL_IF)) timedout = true; } @@ -1114,7 +1118,7 @@ static int panthor_fw_start(struct panthor_device *ptdev) [MCU_STATUS_HALT] = "halt", [MCU_STATUS_FATAL] = "fatal", }; - u32 status = gpu_read(ptdev, MCU_STATUS); + u32 status = gpu_read(fw->iomem, MCU_STATUS); drm_err(&ptdev->base, "Failed to boot MCU (status=%s)", status < ARRAY_SIZE(status_str) ? status_str[status] : "unknown"); @@ -1126,10 +1130,11 @@ static int panthor_fw_start(struct panthor_device *ptdev) static void panthor_fw_stop(struct panthor_device *ptdev) { + struct panthor_fw *fw = ptdev->fw; u32 status; - gpu_write(ptdev, MCU_CONTROL, MCU_CONTROL_DISABLE); - if (gpu_read_poll_timeout(ptdev, MCU_STATUS, status, + gpu_write(fw->iomem, MCU_CONTROL, MCU_CONTROL_DISABLE); + if (gpu_read_poll_timeout(fw->iomem, MCU_STATUS, status, status == MCU_STATUS_DISABLED, 10, 100000)) drm_err(&ptdev->base, "Failed to stop MCU"); } @@ -1139,7 +1144,7 @@ static bool panthor_fw_mcu_halted(struct panthor_device *ptdev) struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); bool halted; - halted = gpu_read(ptdev, MCU_STATUS) == MCU_STATUS_HALT; + halted = gpu_read(ptdev->fw->iomem, MCU_STATUS) == MCU_STATUS_HALT; if (panthor_fw_has_glb_state(ptdev)) halted &= (GLB_STATE_GET(glb_iface->output->ack) == GLB_STATE_HALT); @@ -1156,7 +1161,7 @@ static void panthor_fw_halt_mcu(struct panthor_device *ptdev) else panthor_fw_update_reqs(glb_iface, req, GLB_HALT, GLB_HALT); - gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); + panthor_fw_ring_doorbell(ptdev, CSF_GLB_DOORBELL_ID); } static bool panthor_fw_wait_mcu_halted(struct panthor_device *ptdev) @@ -1400,6 +1405,11 @@ int panthor_fw_csg_wait_acks(struct panthor_device *ptdev, u32 csg_slot, return ret; } +void panthor_fw_ring_doorbell(struct panthor_device *ptdev, u32 doorbell_id) +{ + gpu_write(ptdev->iomem, CSF_DOORBELL(doorbell_id), 1); +} + /** * panthor_fw_ring_csg_doorbells() - Ring command stream group doorbells. * @ptdev: Device. @@ -1414,7 +1424,7 @@ void panthor_fw_ring_csg_doorbells(struct panthor_device *ptdev, u32 csg_mask) struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); panthor_fw_toggle_reqs(glb_iface, doorbell_req, doorbell_ack, csg_mask); - gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); + panthor_fw_ring_doorbell(ptdev, CSF_GLB_DOORBELL_ID); } static void panthor_fw_ping_work(struct work_struct *work) @@ -1429,7 +1439,7 @@ static void panthor_fw_ping_work(struct work_struct *work) return; panthor_fw_toggle_reqs(glb_iface, req, ack, GLB_PING); - gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); + panthor_fw_ring_doorbell(ptdev, CSF_GLB_DOORBELL_ID); ret = panthor_fw_glb_wait_acks(ptdev, GLB_PING, &acked, 100); if (ret) { @@ -1456,6 +1466,7 @@ int panthor_fw_init(struct panthor_device *ptdev) if (!fw) return -ENOMEM; + fw->iomem = ptdev->iomem + MCU_CONTROL_BASE; ptdev->fw = fw; init_waitqueue_head(&fw->req_waitqueue); INIT_LIST_HEAD(&fw->sections); @@ -1465,7 +1476,8 @@ int panthor_fw_init(struct panthor_device *ptdev) if (irq <= 0) return -ENODEV; - ret = panthor_request_job_irq(ptdev, &fw->irq, irq, 0); + ret = panthor_request_job_irq(ptdev, &fw->irq, irq, 0, + ptdev->iomem + JOB_INT_BASE); if (ret) { drm_err(&ptdev->base, "failed to request job irq"); return ret; diff --git a/drivers/gpu/drm/panthor/panthor_fw.h b/drivers/gpu/drm/panthor/panthor_fw.h index fbdc21469ba3..a99a9b6f4825 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.h +++ b/drivers/gpu/drm/panthor/panthor_fw.h @@ -500,6 +500,7 @@ int panthor_fw_csg_wait_acks(struct panthor_device *ptdev, u32 csg_id, u32 req_m int panthor_fw_glb_wait_acks(struct panthor_device *ptdev, u32 req_mask, u32 *acked, u32 timeout_ms); +void panthor_fw_ring_doorbell(struct panthor_device *ptdev, u32 doorbell_id); void panthor_fw_ring_csg_doorbells(struct panthor_device *ptdev, u32 csg_slot); struct panthor_kernel_bo * diff --git a/drivers/gpu/drm/panthor/panthor_fw_regs.h b/drivers/gpu/drm/panthor/panthor_fw_regs.h new file mode 100644 index 000000000000..b2e59cfc22b0 --- /dev/null +++ b/drivers/gpu/drm/panthor/panthor_fw_regs.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +/* Copyright 2026 ARM Limited. All rights reserved. */ + +#ifndef __PANTHOR_FW_REGS_H__ +#define __PANTHOR_FW_REGS_H__ + +#define MCU_CONTROL_BASE 0x700 + +#define MCU_CONTROL 0x0 +#define MCU_CONTROL_ENABLE 1 +#define MCU_CONTROL_AUTO 2 +#define MCU_CONTROL_DISABLE 0 + +#define MCU_STATUS 0x4 +#define MCU_STATUS_DISABLED 0 +#define MCU_STATUS_ENABLED 1 +#define MCU_STATUS_HALT 2 +#define MCU_STATUS_FATAL 3 + +#define JOB_INT_BASE 0x1000 +#define JOB_INT_GLOBAL_IF BIT(31) +#define JOB_INT_CSG_IF(x) BIT(x) + +#define CSF_GPU_LATEST_FLUSH_ID 0x10000 + +#define CSF_DOORBELL(i) (0x80000 + ((i) * 0x10000)) +#define CSF_GLB_DOORBELL_ID 0 + +#endif /* __PANTHOR_FW_REGS_H__ */ diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c index 2ab444ee8c71..e52c5675981f 100644 --- a/drivers/gpu/drm/panthor/panthor_gpu.c +++ b/drivers/gpu/drm/panthor/panthor_gpu.c @@ -19,8 +19,8 @@ #include "panthor_device.h" #include "panthor_gpu.h" +#include "panthor_gpu_regs.h" #include "panthor_hw.h" -#include "panthor_regs.h" #define CREATE_TRACE_POINTS #include "panthor_trace.h" @@ -29,6 +29,9 @@ * struct panthor_gpu - GPU block management data. */ struct panthor_gpu { + /** @iomem: CPU mapping of GPU_CONTROL iomem region */ + void __iomem *iomem; + /** @irq: GPU irq. */ struct panthor_irq irq; @@ -56,12 +59,13 @@ struct panthor_gpu { static void panthor_gpu_coherency_set(struct panthor_device *ptdev) { - gpu_write(ptdev, GPU_COHERENCY_PROTOCOL, + gpu_write(ptdev->gpu->iomem, GPU_COHERENCY_PROTOCOL, ptdev->gpu_info.selected_coherency); } static void panthor_gpu_l2_config_set(struct panthor_device *ptdev) { + struct panthor_gpu *gpu = ptdev->gpu; const struct panthor_soc_data *data = ptdev->soc_data; u32 l2_config; u32 i; @@ -75,26 +79,28 @@ static void panthor_gpu_l2_config_set(struct panthor_device *ptdev) } for (i = 0; i < ARRAY_SIZE(data->asn_hash); i++) - gpu_write(ptdev, GPU_ASN_HASH(i), data->asn_hash[i]); + gpu_write(gpu->iomem, GPU_ASN_HASH(i), data->asn_hash[i]); - l2_config = gpu_read(ptdev, GPU_L2_CONFIG); + l2_config = gpu_read(gpu->iomem, GPU_L2_CONFIG); l2_config |= GPU_L2_CONFIG_ASN_HASH_ENABLE; - gpu_write(ptdev, GPU_L2_CONFIG, l2_config); + gpu_write(gpu->iomem, GPU_L2_CONFIG, l2_config); } static void panthor_gpu_irq_handler(struct panthor_device *ptdev, u32 status) { - gpu_write(ptdev, GPU_INT_CLEAR, status); + struct panthor_gpu *gpu = ptdev->gpu; + + gpu_write(gpu->irq.iomem, INT_CLEAR, status); if (tracepoint_enabled(gpu_power_status) && (status & GPU_POWER_INTERRUPTS_MASK)) trace_gpu_power_status(ptdev->base.dev, - gpu_read64(ptdev, SHADER_READY), - gpu_read64(ptdev, TILER_READY), - gpu_read64(ptdev, L2_READY)); + gpu_read64(gpu->iomem, SHADER_READY), + gpu_read64(gpu->iomem, TILER_READY), + gpu_read64(gpu->iomem, L2_READY)); if (status & GPU_IRQ_FAULT) { - u32 fault_status = gpu_read(ptdev, GPU_FAULT_STATUS); - u64 address = gpu_read64(ptdev, GPU_FAULT_ADDR); + u32 fault_status = gpu_read(gpu->iomem, GPU_FAULT_STATUS); + u64 address = gpu_read64(gpu->iomem, GPU_FAULT_ADDR); drm_warn(&ptdev->base, "GPU Fault 0x%08x (%s) at 0x%016llx\n", fault_status, panthor_exception_name(ptdev, fault_status & 0xFF), @@ -110,7 +116,7 @@ static void panthor_gpu_irq_handler(struct panthor_device *ptdev, u32 status) } spin_unlock(&ptdev->gpu->reqs_lock); } -PANTHOR_IRQ_HANDLER(gpu, GPU, panthor_gpu_irq_handler); +PANTHOR_IRQ_HANDLER(gpu, panthor_gpu_irq_handler); /** * panthor_gpu_unplug() - Called when the GPU is unplugged. @@ -147,6 +153,7 @@ int panthor_gpu_init(struct panthor_device *ptdev) if (!gpu) return -ENOMEM; + gpu->iomem = ptdev->iomem + GPU_CONTROL_BASE; spin_lock_init(&gpu->reqs_lock); init_waitqueue_head(&gpu->reqs_acked); mutex_init(&gpu->cache_flush_lock); @@ -162,7 +169,9 @@ int panthor_gpu_init(struct panthor_device *ptdev) if (irq < 0) return irq; - ret = panthor_request_gpu_irq(ptdev, &ptdev->gpu->irq, irq, GPU_INTERRUPTS_MASK); + ret = panthor_request_gpu_irq(ptdev, &ptdev->gpu->irq, irq, + GPU_INTERRUPTS_MASK, + ptdev->iomem + GPU_INT_BASE); if (ret) return ret; @@ -201,10 +210,11 @@ int panthor_gpu_block_power_off(struct panthor_device *ptdev, u32 pwroff_reg, u32 pwrtrans_reg, u64 mask, u32 timeout_us) { + struct panthor_gpu *gpu = ptdev->gpu; u32 val; int ret; - ret = gpu_read64_relaxed_poll_timeout(ptdev, pwrtrans_reg, val, + ret = gpu_read64_relaxed_poll_timeout(gpu->iomem, pwrtrans_reg, val, !(mask & val), 100, timeout_us); if (ret) { drm_err(&ptdev->base, @@ -213,9 +223,9 @@ int panthor_gpu_block_power_off(struct panthor_device *ptdev, return ret; } - gpu_write64(ptdev, pwroff_reg, mask); + gpu_write64(gpu->iomem, pwroff_reg, mask); - ret = gpu_read64_relaxed_poll_timeout(ptdev, pwrtrans_reg, val, + ret = gpu_read64_relaxed_poll_timeout(gpu->iomem, pwrtrans_reg, val, !(mask & val), 100, timeout_us); if (ret) { drm_err(&ptdev->base, @@ -244,10 +254,11 @@ int panthor_gpu_block_power_on(struct panthor_device *ptdev, u32 pwron_reg, u32 pwrtrans_reg, u32 rdy_reg, u64 mask, u32 timeout_us) { + struct panthor_gpu *gpu = ptdev->gpu; u32 val; int ret; - ret = gpu_read64_relaxed_poll_timeout(ptdev, pwrtrans_reg, val, + ret = gpu_read64_relaxed_poll_timeout(gpu->iomem, pwrtrans_reg, val, !(mask & val), 100, timeout_us); if (ret) { drm_err(&ptdev->base, @@ -256,9 +267,9 @@ int panthor_gpu_block_power_on(struct panthor_device *ptdev, return ret; } - gpu_write64(ptdev, pwron_reg, mask); + gpu_write64(gpu->iomem, pwron_reg, mask); - ret = gpu_read64_relaxed_poll_timeout(ptdev, rdy_reg, val, + ret = gpu_read64_relaxed_poll_timeout(gpu->iomem, rdy_reg, val, (mask & val) == val, 100, timeout_us); if (ret) { @@ -317,6 +328,7 @@ int panthor_gpu_l2_power_on(struct panthor_device *ptdev) int panthor_gpu_flush_caches(struct panthor_device *ptdev, u32 l2, u32 lsc, u32 other) { + struct panthor_gpu *gpu = ptdev->gpu; unsigned long flags; int ret = 0; @@ -326,7 +338,7 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev, spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) { ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED; - gpu_write(ptdev, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other)); + gpu_write(gpu->iomem, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other)); } else { ret = -EIO; } @@ -340,7 +352,7 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev, msecs_to_jiffies(100))) { spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); if ((ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED) != 0 && - !(gpu_read(ptdev, GPU_INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED)) + !(gpu_read(gpu->irq.iomem, INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED)) ret = -ETIMEDOUT; else ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED; @@ -363,6 +375,7 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev, */ int panthor_gpu_soft_reset(struct panthor_device *ptdev) { + struct panthor_gpu *gpu = ptdev->gpu; bool timedout = false; unsigned long flags; @@ -370,8 +383,8 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev) if (!drm_WARN_ON(&ptdev->base, ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED)) { ptdev->gpu->pending_reqs |= GPU_IRQ_RESET_COMPLETED; - gpu_write(ptdev, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED); - gpu_write(ptdev, GPU_CMD, GPU_SOFT_RESET); + gpu_write(gpu->irq.iomem, INT_CLEAR, GPU_IRQ_RESET_COMPLETED); + gpu_write(gpu->iomem, GPU_CMD, GPU_SOFT_RESET); } spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); @@ -380,7 +393,7 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev) msecs_to_jiffies(100))) { spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); if ((ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED) != 0 && - !(gpu_read(ptdev, GPU_INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED)) + !(gpu_read(gpu->irq.iomem, INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED)) timedout = true; else ptdev->gpu->pending_reqs &= ~GPU_IRQ_RESET_COMPLETED; @@ -427,3 +440,43 @@ void panthor_gpu_resume(struct panthor_device *ptdev) panthor_hw_l2_power_on(ptdev); } +u64 panthor_gpu_get_timestamp(struct panthor_device *ptdev) +{ + return gpu_read64_counter(ptdev->gpu->iomem, GPU_TIMESTAMP); +} + +u64 panthor_gpu_get_timestamp_offset(struct panthor_device *ptdev) +{ + return gpu_read64(ptdev->gpu->iomem, GPU_TIMESTAMP_OFFSET); +} + +u64 panthor_gpu_get_cycle_count(struct panthor_device *ptdev) +{ + return gpu_read64_counter(ptdev->gpu->iomem, GPU_CYCLE_COUNT); +} + +int panthor_gpu_coherency_init(struct panthor_device *ptdev) +{ + BUILD_BUG_ON(GPU_COHERENCY_NONE != DRM_PANTHOR_GPU_COHERENCY_NONE); + BUILD_BUG_ON(GPU_COHERENCY_ACE_LITE != DRM_PANTHOR_GPU_COHERENCY_ACE_LITE); + BUILD_BUG_ON(GPU_COHERENCY_ACE != DRM_PANTHOR_GPU_COHERENCY_ACE); + + /* Start with no coherency, and update it if the device is flagged coherent. */ + ptdev->gpu_info.selected_coherency = GPU_COHERENCY_NONE; + ptdev->coherent = device_get_dma_attr(ptdev->base.dev) == DEV_DMA_COHERENT; + + if (!ptdev->coherent) + return 0; + + /* Check if the ACE-Lite coherency protocol is actually supported by the GPU. + * ACE protocol has never been supported for command stream frontend GPUs. + */ + if ((gpu_read(ptdev->gpu->iomem, GPU_COHERENCY_FEATURES) & + GPU_COHERENCY_PROT_BIT(ACE_LITE))) { + ptdev->gpu_info.selected_coherency = GPU_COHERENCY_ACE_LITE; + return 0; + } + + drm_err(&ptdev->base, "Coherency not supported by the device"); + return -ENOTSUPP; +} diff --git a/drivers/gpu/drm/panthor/panthor_gpu.h b/drivers/gpu/drm/panthor/panthor_gpu.h index 12c263a39928..f615feb05609 100644 --- a/drivers/gpu/drm/panthor/panthor_gpu.h +++ b/drivers/gpu/drm/panthor/panthor_gpu.h @@ -54,4 +54,10 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev); void panthor_gpu_power_changed_off(struct panthor_device *ptdev); int panthor_gpu_power_changed_on(struct panthor_device *ptdev); +u64 panthor_gpu_get_timestamp(struct panthor_device *ptdev); +u64 panthor_gpu_get_timestamp_offset(struct panthor_device *ptdev); +u64 panthor_gpu_get_cycle_count(struct panthor_device *ptdev); + +int panthor_gpu_coherency_init(struct panthor_device *ptdev); + #endif diff --git a/drivers/gpu/drm/panthor/panthor_gpu_regs.h b/drivers/gpu/drm/panthor/panthor_gpu_regs.h new file mode 100644 index 000000000000..4c5b953796e4 --- /dev/null +++ b/drivers/gpu/drm/panthor/panthor_gpu_regs.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +/* Copyright 2026 ARM Limited. All rights reserved. */ + +#ifndef __PANTHOR_GPU_REGS_H__ +#define __PANTHOR_GPU_REGS_H__ + +#define GPU_CONTROL_BASE 0x0 + +#define GPU_ID 0x0 +#define GPU_ARCH_MAJOR(x) ((x) >> 28) +#define GPU_ARCH_MINOR(x) (((x) & GENMASK(27, 24)) >> 24) +#define GPU_ARCH_REV(x) (((x) & GENMASK(23, 20)) >> 20) +#define GPU_PROD_MAJOR(x) (((x) & GENMASK(19, 16)) >> 16) +#define GPU_VER_MAJOR(x) (((x) & GENMASK(15, 12)) >> 12) +#define GPU_VER_MINOR(x) (((x) & GENMASK(11, 4)) >> 4) +#define GPU_VER_STATUS(x) ((x) & GENMASK(3, 0)) + +#define GPU_L2_FEATURES 0x4 +#define GPU_L2_FEATURES_LINE_SIZE(x) (1 << ((x) & GENMASK(7, 0))) + +#define GPU_CORE_FEATURES 0x8 + +#define GPU_TILER_FEATURES 0xC +#define GPU_MEM_FEATURES 0x10 +#define GROUPS_L2_COHERENT BIT(0) + +#define GPU_MMU_FEATURES 0x14 +#define GPU_MMU_FEATURES_VA_BITS(x) ((x) & GENMASK(7, 0)) +#define GPU_MMU_FEATURES_PA_BITS(x) (((x) >> 8) & GENMASK(7, 0)) +#define GPU_AS_PRESENT 0x18 +#define GPU_CSF_ID 0x1C + +#define GPU_INT_BASE 0x20 +#define GPU_IRQ_FAULT BIT(0) +#define GPU_IRQ_PROTM_FAULT BIT(1) +#define GPU_IRQ_RESET_COMPLETED BIT(8) +#define GPU_IRQ_POWER_CHANGED BIT(9) +#define GPU_IRQ_POWER_CHANGED_ALL BIT(10) +#define GPU_IRQ_CLEAN_CACHES_COMPLETED BIT(17) +#define GPU_IRQ_DOORBELL_MIRROR BIT(18) +#define GPU_IRQ_MCU_STATUS_CHANGED BIT(19) +#define GPU_CMD 0x30 +#define GPU_CMD_DEF(type, payload) ((type) | ((payload) << 8)) +#define GPU_SOFT_RESET GPU_CMD_DEF(1, 1) +#define GPU_HARD_RESET GPU_CMD_DEF(1, 2) +#define CACHE_CLEAN BIT(0) +#define CACHE_INV BIT(1) +#define GPU_FLUSH_CACHES(l2, lsc, oth) \ + GPU_CMD_DEF(4, ((l2) << 0) | ((lsc) << 4) | ((oth) << 8)) + +#define GPU_STATUS 0x34 +#define GPU_STATUS_ACTIVE BIT(0) +#define GPU_STATUS_PWR_ACTIVE BIT(1) +#define GPU_STATUS_PAGE_FAULT BIT(4) +#define GPU_STATUS_PROTM_ACTIVE BIT(7) +#define GPU_STATUS_DBG_ENABLED BIT(8) + +#define GPU_FAULT_STATUS 0x3C +#define GPU_FAULT_ADDR 0x40 +#define GPU_L2_CONFIG 0x48 +#define GPU_L2_CONFIG_ASN_HASH_ENABLE BIT(24) + +#define GPU_PWR_KEY 0x50 +#define GPU_PWR_KEY_UNLOCK 0x2968A819 +#define GPU_PWR_OVERRIDE0 0x54 +#define GPU_PWR_OVERRIDE1 0x58 + +#define GPU_FEATURES 0x60 +#define GPU_FEATURES_RAY_INTERSECTION BIT(2) +#define GPU_FEATURES_RAY_TRAVERSAL BIT(5) + +#define GPU_TIMESTAMP_OFFSET 0x88 +#define GPU_CYCLE_COUNT 0x90 +#define GPU_TIMESTAMP 0x98 + +#define GPU_THREAD_MAX_THREADS 0xA0 +#define GPU_THREAD_MAX_WORKGROUP_SIZE 0xA4 +#define GPU_THREAD_MAX_BARRIER_SIZE 0xA8 +#define GPU_THREAD_FEATURES 0xAC + +#define GPU_TEXTURE_FEATURES(n) (0xB0 + ((n) * 4)) + +#define GPU_SHADER_PRESENT 0x100 +#define GPU_TILER_PRESENT 0x110 +#define GPU_L2_PRESENT 0x120 + +#define SHADER_READY 0x140 +#define TILER_READY 0x150 +#define L2_READY 0x160 + +#define SHADER_PWRON 0x180 +#define TILER_PWRON 0x190 +#define L2_PWRON 0x1A0 + +#define SHADER_PWROFF 0x1C0 +#define TILER_PWROFF 0x1D0 +#define L2_PWROFF 0x1E0 + +#define SHADER_PWRTRANS 0x200 +#define TILER_PWRTRANS 0x210 +#define L2_PWRTRANS 0x220 + +#define SHADER_PWRACTIVE 0x240 +#define TILER_PWRACTIVE 0x250 +#define L2_PWRACTIVE 0x260 + +#define GPU_REVID 0x280 + +#define GPU_ASN_HASH(n) (0x2C0 + ((n) * 4)) + +#define GPU_COHERENCY_FEATURES 0x300 +#define GPU_COHERENCY_PROT_BIT(name) BIT(GPU_COHERENCY_ ## name) + +#define GPU_COHERENCY_PROTOCOL 0x304 +#define GPU_COHERENCY_ACE_LITE 0 +#define GPU_COHERENCY_ACE 1 +#define GPU_COHERENCY_NONE 31 + +#endif /* __PANTHOR_GPU_REGS_H__ */ diff --git a/drivers/gpu/drm/panthor/panthor_heap.c b/drivers/gpu/drm/panthor/panthor_heap.c index 1ee30dc7066f..99311abdf1e9 100644 --- a/drivers/gpu/drm/panthor/panthor_heap.c +++ b/drivers/gpu/drm/panthor/panthor_heap.c @@ -9,9 +9,9 @@ #include "panthor_device.h" #include "panthor_gem.h" +#include "panthor_gpu_regs.h" #include "panthor_heap.h" #include "panthor_mmu.h" -#include "panthor_regs.h" /* * The GPU heap context is an opaque structure used by the GPU to track the diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c index d135aa6724fa..7e315708ca7c 100644 --- a/drivers/gpu/drm/panthor/panthor_hw.c +++ b/drivers/gpu/drm/panthor/panthor_hw.c @@ -8,9 +8,10 @@ #include "panthor_device.h" #include "panthor_gpu.h" +#include "panthor_gpu_regs.h" #include "panthor_hw.h" #include "panthor_pwr.h" -#include "panthor_regs.h" +#include "panthor_pwr_regs.h" #define GPU_PROD_ID_MAKE(arch_major, prod_major) \ (((arch_major) << 24) | (prod_major)) @@ -194,35 +195,42 @@ static int panthor_gpu_info_init(struct panthor_device *ptdev) { unsigned int i; - ptdev->gpu_info.csf_id = gpu_read(ptdev, GPU_CSF_ID); - ptdev->gpu_info.gpu_rev = gpu_read(ptdev, GPU_REVID); - ptdev->gpu_info.core_features = gpu_read(ptdev, GPU_CORE_FEATURES); - ptdev->gpu_info.l2_features = gpu_read(ptdev, GPU_L2_FEATURES); - ptdev->gpu_info.tiler_features = gpu_read(ptdev, GPU_TILER_FEATURES); - ptdev->gpu_info.mem_features = gpu_read(ptdev, GPU_MEM_FEATURES); - ptdev->gpu_info.mmu_features = gpu_read(ptdev, GPU_MMU_FEATURES); - ptdev->gpu_info.thread_features = gpu_read(ptdev, GPU_THREAD_FEATURES); - ptdev->gpu_info.max_threads = gpu_read(ptdev, GPU_THREAD_MAX_THREADS); - ptdev->gpu_info.thread_max_workgroup_size = gpu_read(ptdev, GPU_THREAD_MAX_WORKGROUP_SIZE); - ptdev->gpu_info.thread_max_barrier_size = gpu_read(ptdev, GPU_THREAD_MAX_BARRIER_SIZE); - ptdev->gpu_info.coherency_features = gpu_read(ptdev, GPU_COHERENCY_FEATURES); + void __iomem *gpu_iomem = ptdev->iomem + GPU_CONTROL_BASE; + + ptdev->gpu_info.csf_id = gpu_read(gpu_iomem, GPU_CSF_ID); + ptdev->gpu_info.gpu_rev = gpu_read(gpu_iomem, GPU_REVID); + ptdev->gpu_info.core_features = gpu_read(gpu_iomem, GPU_CORE_FEATURES); + ptdev->gpu_info.l2_features = gpu_read(gpu_iomem, GPU_L2_FEATURES); + ptdev->gpu_info.tiler_features = gpu_read(gpu_iomem, GPU_TILER_FEATURES); + ptdev->gpu_info.mem_features = gpu_read(gpu_iomem, GPU_MEM_FEATURES); + ptdev->gpu_info.mmu_features = gpu_read(gpu_iomem, GPU_MMU_FEATURES); + ptdev->gpu_info.thread_features = gpu_read(gpu_iomem, GPU_THREAD_FEATURES); + ptdev->gpu_info.max_threads = gpu_read(gpu_iomem, GPU_THREAD_MAX_THREADS); + ptdev->gpu_info.thread_max_workgroup_size = + gpu_read(gpu_iomem, GPU_THREAD_MAX_WORKGROUP_SIZE); + ptdev->gpu_info.thread_max_barrier_size = + gpu_read(gpu_iomem, GPU_THREAD_MAX_BARRIER_SIZE); + ptdev->gpu_info.coherency_features = gpu_read(gpu_iomem, GPU_COHERENCY_FEATURES); for (i = 0; i < 4; i++) - ptdev->gpu_info.texture_features[i] = gpu_read(ptdev, GPU_TEXTURE_FEATURES(i)); + ptdev->gpu_info.texture_features[i] = + gpu_read(gpu_iomem, GPU_TEXTURE_FEATURES(i)); - ptdev->gpu_info.as_present = gpu_read(ptdev, GPU_AS_PRESENT); + ptdev->gpu_info.as_present = gpu_read(gpu_iomem, GPU_AS_PRESENT); /* Introduced in arch 11.x */ - ptdev->gpu_info.gpu_features = gpu_read64(ptdev, GPU_FEATURES); + ptdev->gpu_info.gpu_features = gpu_read64(gpu_iomem, GPU_FEATURES); if (panthor_hw_has_pwr_ctrl(ptdev)) { + void __iomem *pwr_iomem = gpu_iomem + PWR_CONTROL_BASE; + /* Introduced in arch 14.x */ - ptdev->gpu_info.l2_present = gpu_read64(ptdev, PWR_L2_PRESENT); - ptdev->gpu_info.tiler_present = gpu_read64(ptdev, PWR_TILER_PRESENT); - ptdev->gpu_info.shader_present = gpu_read64(ptdev, PWR_SHADER_PRESENT); + ptdev->gpu_info.l2_present = gpu_read64(pwr_iomem, PWR_L2_PRESENT); + ptdev->gpu_info.tiler_present = gpu_read64(pwr_iomem, PWR_TILER_PRESENT); + ptdev->gpu_info.shader_present = gpu_read64(pwr_iomem, PWR_SHADER_PRESENT); } else { - ptdev->gpu_info.shader_present = gpu_read64(ptdev, GPU_SHADER_PRESENT); - ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT); - ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT); + ptdev->gpu_info.shader_present = gpu_read64(gpu_iomem, GPU_SHADER_PRESENT); + ptdev->gpu_info.tiler_present = gpu_read64(gpu_iomem, GPU_TILER_PRESENT); + ptdev->gpu_info.l2_present = gpu_read64(gpu_iomem, GPU_L2_PRESENT); } return overload_shader_present(ptdev); @@ -287,7 +295,7 @@ static int panthor_hw_bind_device(struct panthor_device *ptdev) static int panthor_hw_gpu_id_init(struct panthor_device *ptdev) { - ptdev->gpu_info.gpu_id = gpu_read(ptdev, GPU_ID); + ptdev->gpu_info.gpu_id = gpu_read(ptdev->iomem, GPU_ID); if (!ptdev->gpu_info.gpu_id) return -ENXIO; diff --git a/drivers/gpu/drm/panthor/panthor_hw.h b/drivers/gpu/drm/panthor/panthor_hw.h index 2c28aea82841..f797663893b2 100644 --- a/drivers/gpu/drm/panthor/panthor_hw.h +++ b/drivers/gpu/drm/panthor/panthor_hw.h @@ -5,7 +5,7 @@ #define __PANTHOR_HW_H__ #include "panthor_device.h" -#include "panthor_regs.h" +#include "panthor_gpu_regs.h" /** * struct panthor_hw_ops - HW operations that are specific to a GPU diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index fc930ee158a5..a7ee14986849 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -33,9 +33,10 @@ #include "panthor_device.h" #include "panthor_gem.h" #include "panthor_gpu.h" +#include "panthor_gpu_regs.h" #include "panthor_heap.h" #include "panthor_mmu.h" -#include "panthor_regs.h" +#include "panthor_mmu_regs.h" #include "panthor_sched.h" #define MAX_AS_SLOTS 32 @@ -54,6 +55,9 @@ struct panthor_as_slot { * struct panthor_mmu - MMU related data */ struct panthor_mmu { + /** @iomem: CPU mapping of MMU_AS_CONTROL iomem region */ + void __iomem *iomem; + /** @irq: The MMU irq. */ struct panthor_irq irq; @@ -516,15 +520,15 @@ static void free_pt(void *cookie, void *data, size_t size) static int wait_ready(struct panthor_device *ptdev, u32 as_nr) { + struct panthor_mmu *mmu = ptdev->mmu; int ret; u32 val; /* Wait for the MMU status to indicate there is no active command, in * case one is pending. */ - ret = gpu_read_relaxed_poll_timeout_atomic(ptdev, AS_STATUS(as_nr), val, - !(val & AS_STATUS_AS_ACTIVE), - 10, 100000); + ret = gpu_read_relaxed_poll_timeout_atomic(mmu->iomem, AS_STATUS(as_nr), val, + !(val & AS_STATUS_AS_ACTIVE), 10, 100000); if (ret) { panthor_device_schedule_reset(ptdev); @@ -541,7 +545,7 @@ static int as_send_cmd_and_wait(struct panthor_device *ptdev, u32 as_nr, u32 cmd /* write AS_COMMAND when MMU is ready to accept another command */ status = wait_ready(ptdev, as_nr); if (!status) { - gpu_write(ptdev, AS_COMMAND(as_nr), cmd); + gpu_write(ptdev->mmu->iomem, AS_COMMAND(as_nr), cmd); status = wait_ready(ptdev, as_nr); } @@ -584,17 +588,19 @@ static u32 panthor_mmu_as_fault_mask(struct panthor_device *ptdev, u32 as) /* Forward declaration to call helpers within as_enable/disable */ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status); -PANTHOR_IRQ_HANDLER(mmu, MMU, panthor_mmu_irq_handler); +PANTHOR_IRQ_HANDLER(mmu, panthor_mmu_irq_handler); static int panthor_mmu_as_enable(struct panthor_device *ptdev, u32 as_nr, u64 transtab, u64 transcfg, u64 memattr) { + struct panthor_mmu *mmu = ptdev->mmu; + panthor_mmu_irq_enable_events(&ptdev->mmu->irq, panthor_mmu_as_fault_mask(ptdev, as_nr)); - gpu_write64(ptdev, AS_TRANSTAB(as_nr), transtab); - gpu_write64(ptdev, AS_MEMATTR(as_nr), memattr); - gpu_write64(ptdev, AS_TRANSCFG(as_nr), transcfg); + gpu_write64(mmu->iomem, AS_TRANSTAB(as_nr), transtab); + gpu_write64(mmu->iomem, AS_MEMATTR(as_nr), memattr); + gpu_write64(mmu->iomem, AS_TRANSCFG(as_nr), transcfg); return as_send_cmd_and_wait(ptdev, as_nr, AS_COMMAND_UPDATE); } @@ -602,6 +608,7 @@ static int panthor_mmu_as_enable(struct panthor_device *ptdev, u32 as_nr, static int panthor_mmu_as_disable(struct panthor_device *ptdev, u32 as_nr, bool recycle_slot) { + struct panthor_mmu *mmu = ptdev->mmu; struct panthor_vm *vm = ptdev->mmu->as.slots[as_nr].vm; int ret; @@ -629,9 +636,9 @@ static int panthor_mmu_as_disable(struct panthor_device *ptdev, u32 as_nr, if (recycle_slot) return 0; - gpu_write64(ptdev, AS_TRANSTAB(as_nr), 0); - gpu_write64(ptdev, AS_MEMATTR(as_nr), 0); - gpu_write64(ptdev, AS_TRANSCFG(as_nr), AS_TRANSCFG_ADRMODE_UNMAPPED); + gpu_write64(mmu->iomem, AS_TRANSTAB(as_nr), 0); + gpu_write64(mmu->iomem, AS_MEMATTR(as_nr), 0); + gpu_write64(mmu->iomem, AS_TRANSCFG(as_nr), AS_TRANSCFG_ADRMODE_UNMAPPED); return as_send_cmd_and_wait(ptdev, as_nr, AS_COMMAND_UPDATE); } @@ -784,7 +791,7 @@ out_enable_as: */ fault_mask = panthor_mmu_as_fault_mask(ptdev, as); if (ptdev->mmu->as.faulty_mask & fault_mask) { - gpu_write(ptdev, MMU_INT_CLEAR, fault_mask); + gpu_write(ptdev->mmu->irq.iomem, INT_CLEAR, fault_mask); ptdev->mmu->as.faulty_mask &= ~fault_mask; } @@ -1731,7 +1738,7 @@ static int panthor_vm_lock_region(struct panthor_vm *vm, u64 start, u64 size) mutex_lock(&ptdev->mmu->as.slots_lock); if (vm->as.id >= 0 && size) { /* Lock the region that needs to be updated */ - gpu_write64(ptdev, AS_LOCKADDR(vm->as.id), + gpu_write64(ptdev->mmu->iomem, AS_LOCKADDR(vm->as.id), pack_region_range(ptdev, &start, &size)); /* If the lock succeeded, update the locked_region info. */ @@ -1780,6 +1787,7 @@ static void panthor_vm_unlock_region(struct panthor_vm *vm) static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status) { + struct panthor_mmu *mmu = ptdev->mmu; bool has_unhandled_faults = false; status = panthor_mmu_fault_mask(ptdev, status); @@ -1792,8 +1800,8 @@ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status) u32 access_type; u32 source_id; - fault_status = gpu_read(ptdev, AS_FAULTSTATUS(as)); - addr = gpu_read64(ptdev, AS_FAULTADDRESS(as)); + fault_status = gpu_read(mmu->iomem, AS_FAULTSTATUS(as)); + addr = gpu_read64(mmu->iomem, AS_FAULTADDRESS(as)); /* decode the fault status */ exception_type = fault_status & 0xFF; @@ -1824,7 +1832,7 @@ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status) * Note that COMPLETED irqs are never cleared, but this is fine * because they are always masked. */ - gpu_write(ptdev, MMU_INT_CLEAR, mask); + gpu_write(mmu->irq.iomem, INT_CLEAR, mask); if (ptdev->mmu->as.slots[as].vm) ptdev->mmu->as.slots[as].vm->unhandled_fault = true; @@ -3240,6 +3248,7 @@ int panthor_mmu_init(struct panthor_device *ptdev) if (ret) return ret; + mmu->iomem = ptdev->iomem + MMU_AS_BASE; ptdev->mmu = mmu; irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev), "mmu"); @@ -3247,7 +3256,8 @@ int panthor_mmu_init(struct panthor_device *ptdev) return -ENODEV; ret = panthor_request_mmu_irq(ptdev, &mmu->irq, irq, - panthor_mmu_fault_mask(ptdev, ~0)); + panthor_mmu_fault_mask(ptdev, ~0), + ptdev->iomem + MMU_INT_BASE); if (ret) return ret; diff --git a/drivers/gpu/drm/panthor/panthor_mmu_regs.h b/drivers/gpu/drm/panthor/panthor_mmu_regs.h new file mode 100644 index 000000000000..4e32ab931949 --- /dev/null +++ b/drivers/gpu/drm/panthor/panthor_mmu_regs.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +/* Copyright 2026 ARM Limited. All rights reserved. */ + +#ifndef __PANTHOR_MMU_REGS_H__ +#define __PANTHOR_MMU_REGS_H__ + +/* MMU regs */ + +#define MMU_INT_BASE 0x2000 + +/* AS_COMMAND register commands */ + +#define MMU_AS_BASE 0x2400 + +#define MMU_AS_SHIFT 6 +#define MMU_AS(as) ((as) << MMU_AS_SHIFT) + +#define AS_TRANSTAB(as) (MMU_AS(as) + 0x0) +#define AS_MEMATTR(as) (MMU_AS(as) + 0x8) +#define AS_MEMATTR_AARCH64_INNER_ALLOC_IMPL (2 << 2) +#define AS_MEMATTR_AARCH64_INNER_ALLOC_EXPL(w, r) ((3 << 2) | \ + ((w) ? BIT(0) : 0) | \ + ((r) ? BIT(1) : 0)) +#define AS_MEMATTR_AARCH64_SH_MIDGARD_INNER (0 << 4) +#define AS_MEMATTR_AARCH64_SH_CPU_INNER (1 << 4) +#define AS_MEMATTR_AARCH64_SH_CPU_INNER_SHADER_COH (2 << 4) +#define AS_MEMATTR_AARCH64_SHARED (0 << 6) +#define AS_MEMATTR_AARCH64_INNER_OUTER_NC (1 << 6) +#define AS_MEMATTR_AARCH64_INNER_OUTER_WB (2 << 6) +#define AS_MEMATTR_AARCH64_FAULT (3 << 6) +#define AS_LOCKADDR(as) (MMU_AS(as) + 0x10) +#define AS_COMMAND(as) (MMU_AS(as) + 0x18) +#define AS_COMMAND_NOP 0 +#define AS_COMMAND_UPDATE 1 +#define AS_COMMAND_LOCK 2 +#define AS_COMMAND_UNLOCK 3 +#define AS_COMMAND_FLUSH_PT 4 +#define AS_COMMAND_FLUSH_MEM 5 +#define AS_LOCK_REGION_MIN_SIZE (1ULL << 15) +#define AS_FAULTSTATUS(as) (MMU_AS(as) + 0x1C) +#define AS_FAULTSTATUS_ACCESS_TYPE_MASK (0x3 << 8) +#define AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC (0x0 << 8) +#define AS_FAULTSTATUS_ACCESS_TYPE_EX (0x1 << 8) +#define AS_FAULTSTATUS_ACCESS_TYPE_READ (0x2 << 8) +#define AS_FAULTSTATUS_ACCESS_TYPE_WRITE (0x3 << 8) +#define AS_FAULTADDRESS(as) (MMU_AS(as) + 0x20) +#define AS_STATUS(as) (MMU_AS(as) + 0x28) +#define AS_STATUS_AS_ACTIVE BIT(0) +#define AS_TRANSCFG(as) (MMU_AS(as) + 0x30) +#define AS_TRANSCFG_ADRMODE_UNMAPPED (1 << 0) +#define AS_TRANSCFG_ADRMODE_IDENTITY (2 << 0) +#define AS_TRANSCFG_ADRMODE_AARCH64_4K (6 << 0) +#define AS_TRANSCFG_ADRMODE_AARCH64_64K (8 << 0) +#define AS_TRANSCFG_INA_BITS(x) ((x) << 6) +#define AS_TRANSCFG_OUTA_BITS(x) ((x) << 14) +#define AS_TRANSCFG_SL_CONCAT BIT(22) +#define AS_TRANSCFG_PTW_MEMATTR_NC (1 << 24) +#define AS_TRANSCFG_PTW_MEMATTR_WB (2 << 24) +#define AS_TRANSCFG_PTW_SH_NS (0 << 28) +#define AS_TRANSCFG_PTW_SH_OS (2 << 28) +#define AS_TRANSCFG_PTW_SH_IS (3 << 28) +#define AS_TRANSCFG_PTW_RA BIT(30) +#define AS_TRANSCFG_DISABLE_HIER_AP BIT(33) +#define AS_TRANSCFG_DISABLE_AF_FAULT BIT(34) +#define AS_TRANSCFG_WXN BIT(35) +#define AS_TRANSCFG_XREADABLE BIT(36) +#define AS_FAULTEXTRA(as) (MMU_AS(as) + 0x38) + +#endif /* __PANTHOR_MMU_REGS_H__ */ diff --git a/drivers/gpu/drm/panthor/panthor_pwr.c b/drivers/gpu/drm/panthor/panthor_pwr.c index ed3b2b4479ca..7c7f424a1436 100644 --- a/drivers/gpu/drm/panthor/panthor_pwr.c +++ b/drivers/gpu/drm/panthor/panthor_pwr.c @@ -11,9 +11,10 @@ #include <drm/drm_print.h> #include "panthor_device.h" +#include "panthor_gpu_regs.h" #include "panthor_hw.h" #include "panthor_pwr.h" -#include "panthor_regs.h" +#include "panthor_pwr_regs.h" #define PWR_INTERRUPTS_MASK \ (PWR_IRQ_POWER_CHANGED_SINGLE | \ @@ -39,6 +40,9 @@ * struct panthor_pwr - PWR_CONTROL block management data. */ struct panthor_pwr { + /** @iomem: CPU mapping of PWR_CONTROL iomem region */ + void __iomem *iomem; + /** @irq: PWR irq. */ struct panthor_irq irq; @@ -54,8 +58,10 @@ struct panthor_pwr { static void panthor_pwr_irq_handler(struct panthor_device *ptdev, u32 status) { + struct panthor_pwr *pwr = ptdev->pwr; + spin_lock(&ptdev->pwr->reqs_lock); - gpu_write(ptdev, PWR_INT_CLEAR, status); + gpu_write(pwr->irq.iomem, INT_CLEAR, status); if (unlikely(status & PWR_IRQ_COMMAND_NOT_ALLOWED)) drm_err(&ptdev->base, "PWR_IRQ: COMMAND_NOT_ALLOWED"); @@ -69,19 +75,23 @@ static void panthor_pwr_irq_handler(struct panthor_device *ptdev, u32 status) } spin_unlock(&ptdev->pwr->reqs_lock); } -PANTHOR_IRQ_HANDLER(pwr, PWR, panthor_pwr_irq_handler); +PANTHOR_IRQ_HANDLER(pwr, panthor_pwr_irq_handler); static void panthor_pwr_write_command(struct panthor_device *ptdev, u32 command, u64 args) { + struct panthor_pwr *pwr = ptdev->pwr; + if (args) - gpu_write64(ptdev, PWR_CMDARG, args); + gpu_write64(pwr->iomem, PWR_CMDARG, args); - gpu_write(ptdev, PWR_COMMAND, command); + gpu_write(pwr->iomem, PWR_COMMAND, command); } static bool reset_irq_raised(struct panthor_device *ptdev) { - return gpu_read(ptdev, PWR_INT_RAWSTAT) & PWR_IRQ_RESET_COMPLETED; + struct panthor_pwr *pwr = ptdev->pwr; + + return gpu_read(pwr->irq.iomem, INT_RAWSTAT) & PWR_IRQ_RESET_COMPLETED; } static bool reset_pending(struct panthor_device *ptdev) @@ -91,12 +101,14 @@ static bool reset_pending(struct panthor_device *ptdev) static int panthor_pwr_reset(struct panthor_device *ptdev, u32 reset_cmd) { + struct panthor_pwr *pwr = ptdev->pwr; + scoped_guard(spinlock_irqsave, &ptdev->pwr->reqs_lock) { if (reset_pending(ptdev)) { drm_WARN(&ptdev->base, 1, "Reset already pending"); } else { ptdev->pwr->pending_reqs |= PWR_IRQ_RESET_COMPLETED; - gpu_write(ptdev, PWR_INT_CLEAR, PWR_IRQ_RESET_COMPLETED); + gpu_write(pwr->irq.iomem, INT_CLEAR, PWR_IRQ_RESET_COMPLETED); panthor_pwr_write_command(ptdev, reset_cmd, 0); } } @@ -181,11 +193,12 @@ static u8 get_domain_subdomain(struct panthor_device *ptdev, u32 domain) static int panthor_pwr_domain_wait_transition(struct panthor_device *ptdev, u32 domain, u32 timeout_us) { + struct panthor_pwr *pwr = ptdev->pwr; u32 pwrtrans_reg = get_domain_pwrtrans_reg(domain); u64 val; int ret = 0; - ret = gpu_read64_poll_timeout(ptdev, pwrtrans_reg, val, !(PWR_ALL_CORES_MASK & val), 100, + ret = gpu_read64_poll_timeout(pwr->iomem, pwrtrans_reg, val, !(PWR_ALL_CORES_MASK & val), 100, timeout_us); if (ret) { drm_err(&ptdev->base, "%s domain power in transition, pwrtrans(0x%llx)", @@ -198,22 +211,25 @@ static int panthor_pwr_domain_wait_transition(struct panthor_device *ptdev, u32 static void panthor_pwr_debug_info_show(struct panthor_device *ptdev) { - drm_info(&ptdev->base, "GPU_FEATURES: 0x%016llx", gpu_read64(ptdev, GPU_FEATURES)); - drm_info(&ptdev->base, "PWR_STATUS: 0x%016llx", gpu_read64(ptdev, PWR_STATUS)); - drm_info(&ptdev->base, "L2_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_L2_PRESENT)); - drm_info(&ptdev->base, "L2_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_L2_PWRTRANS)); - drm_info(&ptdev->base, "L2_READY: 0x%016llx", gpu_read64(ptdev, PWR_L2_READY)); - drm_info(&ptdev->base, "TILER_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_TILER_PRESENT)); - drm_info(&ptdev->base, "TILER_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_TILER_PWRTRANS)); - drm_info(&ptdev->base, "TILER_READY: 0x%016llx", gpu_read64(ptdev, PWR_TILER_READY)); - drm_info(&ptdev->base, "SHADER_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_PRESENT)); - drm_info(&ptdev->base, "SHADER_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_PWRTRANS)); - drm_info(&ptdev->base, "SHADER_READY: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_READY)); + struct panthor_pwr *pwr = ptdev->pwr; + + drm_info(&ptdev->base, "GPU_FEATURES: 0x%016llx", ptdev->gpu_info.gpu_features); + drm_info(&ptdev->base, "PWR_STATUS: 0x%016llx", gpu_read64(pwr->iomem, PWR_STATUS)); + drm_info(&ptdev->base, "L2_PRESENT: 0x%016llx", gpu_read64(pwr->iomem, PWR_L2_PRESENT)); + drm_info(&ptdev->base, "L2_PWRTRANS: 0x%016llx", gpu_read64(pwr->iomem, PWR_L2_PWRTRANS)); + drm_info(&ptdev->base, "L2_READY: 0x%016llx", gpu_read64(pwr->iomem, PWR_L2_READY)); + drm_info(&ptdev->base, "TILER_PRESENT: 0x%016llx", gpu_read64(pwr->iomem, PWR_TILER_PRESENT)); + drm_info(&ptdev->base, "TILER_PWRTRANS: 0x%016llx", gpu_read64(pwr->iomem, PWR_TILER_PWRTRANS)); + drm_info(&ptdev->base, "TILER_READY: 0x%016llx", gpu_read64(pwr->iomem, PWR_TILER_READY)); + drm_info(&ptdev->base, "SHADER_PRESENT: 0x%016llx", gpu_read64(pwr->iomem, PWR_SHADER_PRESENT)); + drm_info(&ptdev->base, "SHADER_PWRTRANS: 0x%016llx", gpu_read64(pwr->iomem, PWR_SHADER_PWRTRANS)); + drm_info(&ptdev->base, "SHADER_READY: 0x%016llx", gpu_read64(pwr->iomem, PWR_SHADER_READY)); } static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd, u32 domain, u64 mask, u32 timeout_us) { + struct panthor_pwr *pwr = ptdev->pwr; u32 ready_reg = get_domain_ready_reg(domain); u32 pwr_cmd = PWR_COMMAND_DEF(cmd, domain, get_domain_subdomain(ptdev, domain)); u64 expected_val = 0; @@ -240,13 +256,13 @@ static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd, return ret; /* domain already in target state, return early */ - if ((gpu_read64(ptdev, ready_reg) & mask) == expected_val) + if ((gpu_read64(pwr->iomem, ready_reg) & mask) == expected_val) return 0; panthor_pwr_write_command(ptdev, pwr_cmd, mask); - ret = gpu_read64_poll_timeout(ptdev, ready_reg, val, (mask & val) == expected_val, 100, - timeout_us); + ret = gpu_read64_poll_timeout(pwr->iomem, ready_reg, val, (mask & val) == expected_val, + 100, timeout_us); if (ret) { drm_err(&ptdev->base, "timeout waiting on %s power domain transition, cmd(0x%x), arg(0x%llx)", @@ -278,8 +294,9 @@ static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd, */ static int retract_domain(struct panthor_device *ptdev, u32 domain) { + struct panthor_pwr *pwr = ptdev->pwr; const u32 pwr_cmd = PWR_COMMAND_DEF(PWR_COMMAND_RETRACT, domain, 0); - const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS); + const u64 pwr_status = gpu_read64(pwr->iomem, PWR_STATUS); const u64 delegated_mask = PWR_STATUS_DOMAIN_DELEGATED(domain); const u64 allow_mask = PWR_STATUS_DOMAIN_ALLOWED(domain); u64 val; @@ -288,8 +305,9 @@ static int retract_domain(struct panthor_device *ptdev, u32 domain) if (drm_WARN_ON(&ptdev->base, domain == PWR_COMMAND_DOMAIN_L2)) return -EPERM; - ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val, !(PWR_STATUS_RETRACT_PENDING & val), - 0, PWR_RETRACT_TIMEOUT_US); + ret = gpu_read64_poll_timeout(pwr->iomem, PWR_STATUS, val, + !(PWR_STATUS_RETRACT_PENDING & val), 0, + PWR_RETRACT_TIMEOUT_US); if (ret) { drm_err(&ptdev->base, "%s domain retract pending", get_domain_name(domain)); return ret; @@ -306,7 +324,7 @@ static int retract_domain(struct panthor_device *ptdev, u32 domain) * On successful retraction * allow-flag will be set with delegated-flag being cleared. */ - ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val, + ret = gpu_read64_poll_timeout(pwr->iomem, PWR_STATUS, val, ((delegated_mask | allow_mask) & val) == allow_mask, 10, PWR_TRANSITION_TIMEOUT_US); if (ret) { @@ -332,8 +350,9 @@ static int retract_domain(struct panthor_device *ptdev, u32 domain) */ static int delegate_domain(struct panthor_device *ptdev, u32 domain) { + struct panthor_pwr *pwr = ptdev->pwr; const u32 pwr_cmd = PWR_COMMAND_DEF(PWR_COMMAND_DELEGATE, domain, 0); - const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS); + const u64 pwr_status = gpu_read64(pwr->iomem, PWR_STATUS); const u64 allow_mask = PWR_STATUS_DOMAIN_ALLOWED(domain); const u64 delegated_mask = PWR_STATUS_DOMAIN_DELEGATED(domain); u64 val; @@ -362,7 +381,7 @@ static int delegate_domain(struct panthor_device *ptdev, u32 domain) * On successful delegation * allow-flag will be cleared with delegated-flag being set. */ - ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val, + ret = gpu_read64_poll_timeout(pwr->iomem, PWR_STATUS, val, ((delegated_mask | allow_mask) & val) == delegated_mask, 10, PWR_TRANSITION_TIMEOUT_US); if (ret) { @@ -410,7 +429,8 @@ err_retract_shader: */ static int panthor_pwr_domain_force_off(struct panthor_device *ptdev, u32 domain) { - const u64 domain_ready = gpu_read64(ptdev, get_domain_ready_reg(domain)); + struct panthor_pwr *pwr = ptdev->pwr; + const u64 domain_ready = gpu_read64(pwr->iomem, get_domain_ready_reg(domain)); int ret; /* Domain already powered down, early exit. */ @@ -454,6 +474,7 @@ int panthor_pwr_init(struct panthor_device *ptdev) if (!pwr) return -ENOMEM; + pwr->iomem = ptdev->iomem + PWR_CONTROL_BASE; spin_lock_init(&pwr->reqs_lock); init_waitqueue_head(&pwr->reqs_acked); ptdev->pwr = pwr; @@ -462,7 +483,9 @@ int panthor_pwr_init(struct panthor_device *ptdev) if (irq < 0) return irq; - err = panthor_request_pwr_irq(ptdev, &pwr->irq, irq, PWR_INTERRUPTS_MASK); + err = panthor_request_pwr_irq( + ptdev, &pwr->irq, irq, PWR_INTERRUPTS_MASK, + pwr->iomem + PWR_INT_BASE); if (err) return err; @@ -471,7 +494,9 @@ int panthor_pwr_init(struct panthor_device *ptdev) int panthor_pwr_reset_soft(struct panthor_device *ptdev) { - if (!(gpu_read64(ptdev, PWR_STATUS) & PWR_STATUS_ALLOW_SOFT_RESET)) { + struct panthor_pwr *pwr = ptdev->pwr; + + if (!(gpu_read64(pwr->iomem, PWR_STATUS) & PWR_STATUS_ALLOW_SOFT_RESET)) { drm_err(&ptdev->base, "RESET_SOFT not allowed"); return -EOPNOTSUPP; } @@ -481,8 +506,9 @@ int panthor_pwr_reset_soft(struct panthor_device *ptdev) void panthor_pwr_l2_power_off(struct panthor_device *ptdev) { + struct panthor_pwr *pwr = ptdev->pwr; const u64 l2_allow_mask = PWR_STATUS_DOMAIN_ALLOWED(PWR_COMMAND_DOMAIN_L2); - const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS); + const u64 pwr_status = gpu_read64(pwr->iomem, PWR_STATUS); /* Abort if L2 power off constraints are not satisfied */ if (!(pwr_status & l2_allow_mask)) { @@ -508,7 +534,8 @@ void panthor_pwr_l2_power_off(struct panthor_device *ptdev) int panthor_pwr_l2_power_on(struct panthor_device *ptdev) { - const u32 pwr_status = gpu_read64(ptdev, PWR_STATUS); + struct panthor_pwr *pwr = ptdev->pwr; + const u32 pwr_status = gpu_read64(pwr->iomem, PWR_STATUS); const u32 l2_allow_mask = PWR_STATUS_DOMAIN_ALLOWED(PWR_COMMAND_DOMAIN_L2); int ret; diff --git a/drivers/gpu/drm/panthor/panthor_pwr_regs.h b/drivers/gpu/drm/panthor/panthor_pwr_regs.h new file mode 100644 index 000000000000..9cf7a715066f --- /dev/null +++ b/drivers/gpu/drm/panthor/panthor_pwr_regs.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +/* Copyright 2026 ARM Limited. All rights reserved. */ + +#ifndef __PANTHOR_PWR_REGS_H__ +#define __PANTHOR_PWR_REGS_H__ + +#define PWR_CONTROL_BASE 0x800 + +#define PWR_INT_BASE 0x0 +#define PWR_IRQ_POWER_CHANGED_SINGLE BIT(0) +#define PWR_IRQ_POWER_CHANGED_ALL BIT(1) +#define PWR_IRQ_DELEGATION_CHANGED BIT(2) +#define PWR_IRQ_RESET_COMPLETED BIT(3) +#define PWR_IRQ_RETRACT_COMPLETED BIT(4) +#define PWR_IRQ_INSPECT_COMPLETED BIT(5) +#define PWR_IRQ_COMMAND_NOT_ALLOWED BIT(30) +#define PWR_IRQ_COMMAND_INVALID BIT(31) + +#define PWR_STATUS 0x20 +#define PWR_STATUS_ALLOW_L2 BIT_U64(0) +#define PWR_STATUS_ALLOW_TILER BIT_U64(1) +#define PWR_STATUS_ALLOW_SHADER BIT_U64(8) +#define PWR_STATUS_ALLOW_BASE BIT_U64(14) +#define PWR_STATUS_ALLOW_STACK BIT_U64(15) +#define PWR_STATUS_DOMAIN_ALLOWED(x) BIT_U64(x) +#define PWR_STATUS_DELEGATED_L2 BIT_U64(16) +#define PWR_STATUS_DELEGATED_TILER BIT_U64(17) +#define PWR_STATUS_DELEGATED_SHADER BIT_U64(24) +#define PWR_STATUS_DELEGATED_BASE BIT_U64(30) +#define PWR_STATUS_DELEGATED_STACK BIT_U64(31) +#define PWR_STATUS_DELEGATED_SHIFT 16 +#define PWR_STATUS_DOMAIN_DELEGATED(x) BIT_U64((x) + PWR_STATUS_DELEGATED_SHIFT) +#define PWR_STATUS_ALLOW_SOFT_RESET BIT_U64(33) +#define PWR_STATUS_ALLOW_FAST_RESET BIT_U64(34) +#define PWR_STATUS_POWER_PENDING BIT_U64(41) +#define PWR_STATUS_RESET_PENDING BIT_U64(42) +#define PWR_STATUS_RETRACT_PENDING BIT_U64(43) +#define PWR_STATUS_INSPECT_PENDING BIT_U64(44) + +#define PWR_COMMAND 0x28 +#define PWR_COMMAND_POWER_UP 0x10 +#define PWR_COMMAND_POWER_DOWN 0x11 +#define PWR_COMMAND_DELEGATE 0x20 +#define PWR_COMMAND_RETRACT 0x21 +#define PWR_COMMAND_RESET_SOFT 0x31 +#define PWR_COMMAND_RESET_FAST 0x32 +#define PWR_COMMAND_INSPECT 0xF0 +#define PWR_COMMAND_DOMAIN_L2 0 +#define PWR_COMMAND_DOMAIN_TILER 1 +#define PWR_COMMAND_DOMAIN_SHADER 8 +#define PWR_COMMAND_DOMAIN_BASE 14 +#define PWR_COMMAND_DOMAIN_STACK 15 +#define PWR_COMMAND_SUBDOMAIN_RTU BIT(0) +#define PWR_COMMAND_DEF(cmd, domain, subdomain) \ + (((subdomain) << 16) | ((domain) << 8) | (cmd)) + +#define PWR_CMDARG 0x30 + +#define PWR_L2_PRESENT 0x100 +#define PWR_L2_READY 0x108 +#define PWR_L2_PWRTRANS 0x110 +#define PWR_L2_PWRACTIVE 0x118 +#define PWR_TILER_PRESENT 0x140 +#define PWR_TILER_READY 0x148 +#define PWR_TILER_PWRTRANS 0x150 +#define PWR_TILER_PWRACTIVE 0x158 +#define PWR_SHADER_PRESENT 0x200 +#define PWR_SHADER_READY 0x208 +#define PWR_SHADER_PWRTRANS 0x210 +#define PWR_SHADER_PWRACTIVE 0x218 +#define PWR_BASE_PRESENT 0x380 +#define PWR_BASE_READY 0x388 +#define PWR_BASE_PWRTRANS 0x390 +#define PWR_BASE_PWRACTIVE 0x398 +#define PWR_STACK_PRESENT 0x3c0 +#define PWR_STACK_READY 0x3c8 +#define PWR_STACK_PWRTRANS 0x3d0 + +#endif /* __PANTHOR_PWR_REGS_H__ */ diff --git a/drivers/gpu/drm/panthor/panthor_regs.h b/drivers/gpu/drm/panthor/panthor_regs.h deleted file mode 100644 index 08bf06c452d6..000000000000 --- a/drivers/gpu/drm/panthor/panthor_regs.h +++ /dev/null @@ -1,291 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 or MIT */ -/* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */ -/* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */ -/* Copyright 2023 Collabora ltd. */ -/* - * Register definitions based on mali_kbase_gpu_regmap.h and - * mali_kbase_gpu_regmap_csf.h - * (C) COPYRIGHT 2010-2022 ARM Limited. All rights reserved. - */ -#ifndef __PANTHOR_REGS_H__ -#define __PANTHOR_REGS_H__ - -#define GPU_ID 0x0 -#define GPU_ARCH_MAJOR(x) ((x) >> 28) -#define GPU_ARCH_MINOR(x) (((x) & GENMASK(27, 24)) >> 24) -#define GPU_ARCH_REV(x) (((x) & GENMASK(23, 20)) >> 20) -#define GPU_PROD_MAJOR(x) (((x) & GENMASK(19, 16)) >> 16) -#define GPU_VER_MAJOR(x) (((x) & GENMASK(15, 12)) >> 12) -#define GPU_VER_MINOR(x) (((x) & GENMASK(11, 4)) >> 4) -#define GPU_VER_STATUS(x) ((x) & GENMASK(3, 0)) - -#define GPU_L2_FEATURES 0x4 -#define GPU_L2_FEATURES_LINE_SIZE(x) (1 << ((x) & GENMASK(7, 0))) - -#define GPU_CORE_FEATURES 0x8 - -#define GPU_TILER_FEATURES 0xC -#define GPU_MEM_FEATURES 0x10 -#define GROUPS_L2_COHERENT BIT(0) - -#define GPU_MMU_FEATURES 0x14 -#define GPU_MMU_FEATURES_VA_BITS(x) ((x) & GENMASK(7, 0)) -#define GPU_MMU_FEATURES_PA_BITS(x) (((x) >> 8) & GENMASK(7, 0)) -#define GPU_AS_PRESENT 0x18 -#define GPU_CSF_ID 0x1C - -#define GPU_INT_RAWSTAT 0x20 -#define GPU_INT_CLEAR 0x24 -#define GPU_INT_MASK 0x28 -#define GPU_INT_STAT 0x2c -#define GPU_IRQ_FAULT BIT(0) -#define GPU_IRQ_PROTM_FAULT BIT(1) -#define GPU_IRQ_RESET_COMPLETED BIT(8) -#define GPU_IRQ_POWER_CHANGED BIT(9) -#define GPU_IRQ_POWER_CHANGED_ALL BIT(10) -#define GPU_IRQ_CLEAN_CACHES_COMPLETED BIT(17) -#define GPU_IRQ_DOORBELL_MIRROR BIT(18) -#define GPU_IRQ_MCU_STATUS_CHANGED BIT(19) -#define GPU_CMD 0x30 -#define GPU_CMD_DEF(type, payload) ((type) | ((payload) << 8)) -#define GPU_SOFT_RESET GPU_CMD_DEF(1, 1) -#define GPU_HARD_RESET GPU_CMD_DEF(1, 2) -#define CACHE_CLEAN BIT(0) -#define CACHE_INV BIT(1) -#define GPU_FLUSH_CACHES(l2, lsc, oth) \ - GPU_CMD_DEF(4, ((l2) << 0) | ((lsc) << 4) | ((oth) << 8)) - -#define GPU_STATUS 0x34 -#define GPU_STATUS_ACTIVE BIT(0) -#define GPU_STATUS_PWR_ACTIVE BIT(1) -#define GPU_STATUS_PAGE_FAULT BIT(4) -#define GPU_STATUS_PROTM_ACTIVE BIT(7) -#define GPU_STATUS_DBG_ENABLED BIT(8) - -#define GPU_FAULT_STATUS 0x3C -#define GPU_FAULT_ADDR 0x40 -#define GPU_L2_CONFIG 0x48 -#define GPU_L2_CONFIG_ASN_HASH_ENABLE BIT(24) - -#define GPU_PWR_KEY 0x50 -#define GPU_PWR_KEY_UNLOCK 0x2968A819 -#define GPU_PWR_OVERRIDE0 0x54 -#define GPU_PWR_OVERRIDE1 0x58 - -#define GPU_FEATURES 0x60 -#define GPU_FEATURES_RAY_INTERSECTION BIT(2) -#define GPU_FEATURES_RAY_TRAVERSAL BIT(5) - -#define GPU_TIMESTAMP_OFFSET 0x88 -#define GPU_CYCLE_COUNT 0x90 -#define GPU_TIMESTAMP 0x98 - -#define GPU_THREAD_MAX_THREADS 0xA0 -#define GPU_THREAD_MAX_WORKGROUP_SIZE 0xA4 -#define GPU_THREAD_MAX_BARRIER_SIZE 0xA8 -#define GPU_THREAD_FEATURES 0xAC - -#define GPU_TEXTURE_FEATURES(n) (0xB0 + ((n) * 4)) - -#define GPU_SHADER_PRESENT 0x100 -#define GPU_TILER_PRESENT 0x110 -#define GPU_L2_PRESENT 0x120 - -#define SHADER_READY 0x140 -#define TILER_READY 0x150 -#define L2_READY 0x160 - -#define SHADER_PWRON 0x180 -#define TILER_PWRON 0x190 -#define L2_PWRON 0x1A0 - -#define SHADER_PWROFF 0x1C0 -#define TILER_PWROFF 0x1D0 -#define L2_PWROFF 0x1E0 - -#define SHADER_PWRTRANS 0x200 -#define TILER_PWRTRANS 0x210 -#define L2_PWRTRANS 0x220 - -#define SHADER_PWRACTIVE 0x240 -#define TILER_PWRACTIVE 0x250 -#define L2_PWRACTIVE 0x260 - -#define GPU_REVID 0x280 - -#define GPU_ASN_HASH(n) (0x2C0 + ((n) * 4)) - -#define GPU_COHERENCY_FEATURES 0x300 -#define GPU_COHERENCY_PROT_BIT(name) BIT(GPU_COHERENCY_ ## name) - -#define GPU_COHERENCY_PROTOCOL 0x304 -#define GPU_COHERENCY_ACE_LITE 0 -#define GPU_COHERENCY_ACE 1 -#define GPU_COHERENCY_NONE 31 - -#define MCU_CONTROL 0x700 -#define MCU_CONTROL_ENABLE 1 -#define MCU_CONTROL_AUTO 2 -#define MCU_CONTROL_DISABLE 0 - -#define MCU_STATUS 0x704 -#define MCU_STATUS_DISABLED 0 -#define MCU_STATUS_ENABLED 1 -#define MCU_STATUS_HALT 2 -#define MCU_STATUS_FATAL 3 - -/* Job Control regs */ -#define JOB_INT_RAWSTAT 0x1000 -#define JOB_INT_CLEAR 0x1004 -#define JOB_INT_MASK 0x1008 -#define JOB_INT_STAT 0x100c -#define JOB_INT_GLOBAL_IF BIT(31) -#define JOB_INT_CSG_IF(x) BIT(x) - -/* MMU regs */ -#define MMU_INT_RAWSTAT 0x2000 -#define MMU_INT_CLEAR 0x2004 -#define MMU_INT_MASK 0x2008 -#define MMU_INT_STAT 0x200c - -/* AS_COMMAND register commands */ - -#define MMU_BASE 0x2400 -#define MMU_AS_SHIFT 6 -#define MMU_AS(as) (MMU_BASE + ((as) << MMU_AS_SHIFT)) - -#define AS_TRANSTAB(as) (MMU_AS(as) + 0x0) -#define AS_MEMATTR(as) (MMU_AS(as) + 0x8) -#define AS_MEMATTR_AARCH64_INNER_ALLOC_IMPL (2 << 2) -#define AS_MEMATTR_AARCH64_INNER_ALLOC_EXPL(w, r) ((3 << 2) | \ - ((w) ? BIT(0) : 0) | \ - ((r) ? BIT(1) : 0)) -#define AS_MEMATTR_AARCH64_SH_MIDGARD_INNER (0 << 4) -#define AS_MEMATTR_AARCH64_SH_CPU_INNER (1 << 4) -#define AS_MEMATTR_AARCH64_SH_CPU_INNER_SHADER_COH (2 << 4) -#define AS_MEMATTR_AARCH64_SHARED (0 << 6) -#define AS_MEMATTR_AARCH64_INNER_OUTER_NC (1 << 6) -#define AS_MEMATTR_AARCH64_INNER_OUTER_WB (2 << 6) -#define AS_MEMATTR_AARCH64_FAULT (3 << 6) -#define AS_LOCKADDR(as) (MMU_AS(as) + 0x10) -#define AS_COMMAND(as) (MMU_AS(as) + 0x18) -#define AS_COMMAND_NOP 0 -#define AS_COMMAND_UPDATE 1 -#define AS_COMMAND_LOCK 2 -#define AS_COMMAND_UNLOCK 3 -#define AS_COMMAND_FLUSH_PT 4 -#define AS_COMMAND_FLUSH_MEM 5 -#define AS_LOCK_REGION_MIN_SIZE (1ULL << 15) -#define AS_FAULTSTATUS(as) (MMU_AS(as) + 0x1C) -#define AS_FAULTSTATUS_ACCESS_TYPE_MASK (0x3 << 8) -#define AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC (0x0 << 8) -#define AS_FAULTSTATUS_ACCESS_TYPE_EX (0x1 << 8) -#define AS_FAULTSTATUS_ACCESS_TYPE_READ (0x2 << 8) -#define AS_FAULTSTATUS_ACCESS_TYPE_WRITE (0x3 << 8) -#define AS_FAULTADDRESS(as) (MMU_AS(as) + 0x20) -#define AS_STATUS(as) (MMU_AS(as) + 0x28) -#define AS_STATUS_AS_ACTIVE BIT(0) -#define AS_TRANSCFG(as) (MMU_AS(as) + 0x30) -#define AS_TRANSCFG_ADRMODE_UNMAPPED (1 << 0) -#define AS_TRANSCFG_ADRMODE_IDENTITY (2 << 0) -#define AS_TRANSCFG_ADRMODE_AARCH64_4K (6 << 0) -#define AS_TRANSCFG_ADRMODE_AARCH64_64K (8 << 0) -#define AS_TRANSCFG_INA_BITS(x) ((x) << 6) -#define AS_TRANSCFG_OUTA_BITS(x) ((x) << 14) -#define AS_TRANSCFG_SL_CONCAT BIT(22) -#define AS_TRANSCFG_PTW_MEMATTR_NC (1 << 24) -#define AS_TRANSCFG_PTW_MEMATTR_WB (2 << 24) -#define AS_TRANSCFG_PTW_SH_NS (0 << 28) -#define AS_TRANSCFG_PTW_SH_OS (2 << 28) -#define AS_TRANSCFG_PTW_SH_IS (3 << 28) -#define AS_TRANSCFG_PTW_RA BIT(30) -#define AS_TRANSCFG_DISABLE_HIER_AP BIT(33) -#define AS_TRANSCFG_DISABLE_AF_FAULT BIT(34) -#define AS_TRANSCFG_WXN BIT(35) -#define AS_TRANSCFG_XREADABLE BIT(36) -#define AS_FAULTEXTRA(as) (MMU_AS(as) + 0x38) - -#define CSF_GPU_LATEST_FLUSH_ID 0x10000 - -#define CSF_DOORBELL(i) (0x80000 + ((i) * 0x10000)) -#define CSF_GLB_DOORBELL_ID 0 - -/* PWR Control registers */ - -#define PWR_CONTROL_BASE 0x800 -#define PWR_CTRL_REG(x) (PWR_CONTROL_BASE + (x)) - -#define PWR_INT_RAWSTAT PWR_CTRL_REG(0x0) -#define PWR_INT_CLEAR PWR_CTRL_REG(0x4) -#define PWR_INT_MASK PWR_CTRL_REG(0x8) -#define PWR_INT_STAT PWR_CTRL_REG(0xc) -#define PWR_IRQ_POWER_CHANGED_SINGLE BIT(0) -#define PWR_IRQ_POWER_CHANGED_ALL BIT(1) -#define PWR_IRQ_DELEGATION_CHANGED BIT(2) -#define PWR_IRQ_RESET_COMPLETED BIT(3) -#define PWR_IRQ_RETRACT_COMPLETED BIT(4) -#define PWR_IRQ_INSPECT_COMPLETED BIT(5) -#define PWR_IRQ_COMMAND_NOT_ALLOWED BIT(30) -#define PWR_IRQ_COMMAND_INVALID BIT(31) - -#define PWR_STATUS PWR_CTRL_REG(0x20) -#define PWR_STATUS_ALLOW_L2 BIT_U64(0) -#define PWR_STATUS_ALLOW_TILER BIT_U64(1) -#define PWR_STATUS_ALLOW_SHADER BIT_U64(8) -#define PWR_STATUS_ALLOW_BASE BIT_U64(14) -#define PWR_STATUS_ALLOW_STACK BIT_U64(15) -#define PWR_STATUS_DOMAIN_ALLOWED(x) BIT_U64(x) -#define PWR_STATUS_DELEGATED_L2 BIT_U64(16) -#define PWR_STATUS_DELEGATED_TILER BIT_U64(17) -#define PWR_STATUS_DELEGATED_SHADER BIT_U64(24) -#define PWR_STATUS_DELEGATED_BASE BIT_U64(30) -#define PWR_STATUS_DELEGATED_STACK BIT_U64(31) -#define PWR_STATUS_DELEGATED_SHIFT 16 -#define PWR_STATUS_DOMAIN_DELEGATED(x) BIT_U64((x) + PWR_STATUS_DELEGATED_SHIFT) -#define PWR_STATUS_ALLOW_SOFT_RESET BIT_U64(33) -#define PWR_STATUS_ALLOW_FAST_RESET BIT_U64(34) -#define PWR_STATUS_POWER_PENDING BIT_U64(41) -#define PWR_STATUS_RESET_PENDING BIT_U64(42) -#define PWR_STATUS_RETRACT_PENDING BIT_U64(43) -#define PWR_STATUS_INSPECT_PENDING BIT_U64(44) - -#define PWR_COMMAND PWR_CTRL_REG(0x28) -#define PWR_COMMAND_POWER_UP 0x10 -#define PWR_COMMAND_POWER_DOWN 0x11 -#define PWR_COMMAND_DELEGATE 0x20 -#define PWR_COMMAND_RETRACT 0x21 -#define PWR_COMMAND_RESET_SOFT 0x31 -#define PWR_COMMAND_RESET_FAST 0x32 -#define PWR_COMMAND_INSPECT 0xF0 -#define PWR_COMMAND_DOMAIN_L2 0 -#define PWR_COMMAND_DOMAIN_TILER 1 -#define PWR_COMMAND_DOMAIN_SHADER 8 -#define PWR_COMMAND_DOMAIN_BASE 14 -#define PWR_COMMAND_DOMAIN_STACK 15 -#define PWR_COMMAND_SUBDOMAIN_RTU BIT(0) -#define PWR_COMMAND_DEF(cmd, domain, subdomain) \ - (((subdomain) << 16) | ((domain) << 8) | (cmd)) - -#define PWR_CMDARG PWR_CTRL_REG(0x30) - -#define PWR_L2_PRESENT PWR_CTRL_REG(0x100) -#define PWR_L2_READY PWR_CTRL_REG(0x108) -#define PWR_L2_PWRTRANS PWR_CTRL_REG(0x110) -#define PWR_L2_PWRACTIVE PWR_CTRL_REG(0x118) -#define PWR_TILER_PRESENT PWR_CTRL_REG(0x140) -#define PWR_TILER_READY PWR_CTRL_REG(0x148) -#define PWR_TILER_PWRTRANS PWR_CTRL_REG(0x150) -#define PWR_TILER_PWRACTIVE PWR_CTRL_REG(0x158) -#define PWR_SHADER_PRESENT PWR_CTRL_REG(0x200) -#define PWR_SHADER_READY PWR_CTRL_REG(0x208) -#define PWR_SHADER_PWRTRANS PWR_CTRL_REG(0x210) -#define PWR_SHADER_PWRACTIVE PWR_CTRL_REG(0x218) -#define PWR_BASE_PRESENT PWR_CTRL_REG(0x380) -#define PWR_BASE_READY PWR_CTRL_REG(0x388) -#define PWR_BASE_PWRTRANS PWR_CTRL_REG(0x390) -#define PWR_BASE_PWRACTIVE PWR_CTRL_REG(0x398) -#define PWR_STACK_PRESENT PWR_CTRL_REG(0x3c0) -#define PWR_STACK_READY PWR_CTRL_REG(0x3c8) -#define PWR_STACK_PWRTRANS PWR_CTRL_REG(0x3d0) - -#endif diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index 41d6369fa9c0..5b34032deff8 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -28,11 +28,12 @@ #include "panthor_devfreq.h" #include "panthor_device.h" #include "panthor_fw.h" +#include "panthor_fw_regs.h" #include "panthor_gem.h" #include "panthor_gpu.h" +#include "panthor_gpu_regs.h" #include "panthor_heap.h" #include "panthor_mmu.h" -#include "panthor_regs.h" #include "panthor_sched.h" /** @@ -3372,7 +3373,7 @@ queue_run_job(struct drm_sched_job *sched_job) if (resume_tick) sched_resume_tick(ptdev); - gpu_write(ptdev, CSF_DOORBELL(queue->doorbell_id), 1); + panthor_fw_ring_doorbell(ptdev, queue->doorbell_id); if (!sched->pm.has_ref && !(group->blocked_queues & BIT(job->queue_idx))) { pm_runtime_get(ptdev->base.dev); diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c index 32ea09d65d76..db2088529b48 100644 --- a/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c @@ -142,7 +142,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, return PTR_ERR(connector); } - return drm_connector_attach_encoder(connector, &renc->base); + return 0; } void rcar_du_encoder_cleanup(struct rcar_du_device *rcdu) diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c index d53068733c66..0e567b57a408 100644 --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c @@ -129,5 +129,5 @@ int rzg2l_du_encoder_init(struct rzg2l_du_device *rcdu, return PTR_ERR(connector); } - return drm_connector_attach_encoder(connector, &renc->base); + return 0; } diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c index 40fd6e1eeab5..a2c864860075 100644 --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c @@ -1445,6 +1445,11 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev) return dev_err_probe(dsi->dev, PTR_ERR(dsi->prstc), "failed to get prst\n"); + dsi->dcs_buf_virt = dmam_alloc_coherent(dsi->dev, RZG2L_DCS_BUF_SIZE, + &dsi->dcs_buf_phys, GFP_KERNEL); + if (!dsi->dcs_buf_virt) + return -ENOMEM; + platform_set_drvdata(pdev, dsi); pm_runtime_enable(dsi->dev); @@ -1477,11 +1482,6 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev) if (ret < 0) goto err_pm_disable; - dsi->dcs_buf_virt = dma_alloc_coherent(dsi->host.dev, RZG2L_DCS_BUF_SIZE, - &dsi->dcs_buf_phys, GFP_KERNEL); - if (!dsi->dcs_buf_virt) - return -ENOMEM; - return 0; err_phy: @@ -1496,8 +1496,6 @@ static void rzg2l_mipi_dsi_remove(struct platform_device *pdev) { struct rzg2l_mipi_dsi *dsi = platform_get_drvdata(pdev); - dma_free_coherent(dsi->host.dev, RZG2L_DCS_BUF_SIZE, dsi->dcs_buf_virt, - dsi->dcs_buf_phys); mipi_dsi_host_unregister(&dsi->host); pm_runtime_disable(&pdev->dev); } diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c index a799069e2f63..1a2b9b68af6f 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c @@ -583,6 +583,13 @@ shmob_drm_connector_init(struct shmob_drm_device *sdev, drm_connector_helper_add(connector, &connector_helper_funcs); + ret = drm_connector_attach_encoder(connector, encoder); + if (ret < 0) { + drm_connector_cleanup(connector); + kfree(scon); + return ERR_PTR(ret); + } + return connector; } @@ -594,7 +601,6 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev, struct drm_encoder *encoder) { struct drm_connector *connector; - int ret; if (sdev->pdata) connector = shmob_drm_connector_init(sdev, encoder); @@ -606,17 +612,9 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev, return PTR_ERR(connector); } - ret = drm_connector_attach_encoder(connector, encoder); - if (ret < 0) - goto error; - connector->dpms = DRM_MODE_DPMS_OFF; sdev->connector = connector; return 0; - -error: - drm_connector_cleanup(connector); - return ret; } diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 936e4558e93d..06072efd7fca 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -395,7 +395,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, goto err_cleanup_encoder; } - return drm_connector_attach_encoder(connector, dp->plat_data.encoder); + return 0; err_cleanup_encoder: dp->encoder.encoder.funcs->destroy(&dp->encoder.encoder); return ret; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index 892fbea9ae9c..190cce9530c8 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -1024,8 +1024,6 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) return ret; } - drm_connector_attach_encoder(connector, encoder); - for (i = 0; i < dp->ports; i++) { port = dp->port[i]; diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c index 81710e8f3fec..32bc73a1d5e4 100644 --- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c @@ -111,7 +111,7 @@ static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void * return dev_err_probe(dev, PTR_ERR(connector), "Failed to init bridge connector"); - return drm_connector_attach_encoder(connector, encoder); + return 0; } static const struct component_ops dw_dp_rockchip_component_ops = { diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c index c78db7f8ab6c..f35484715c2d 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c @@ -603,7 +603,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master, return dev_err_probe(hdmi->dev, PTR_ERR(connector), "Failed to init bridge connector\n"); - return drm_connector_attach_encoder(connector, encoder); + return 0; } static void dw_hdmi_qp_rockchip_unbind(struct device *dev, diff --git a/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c index 28e6fb09aae7..45a6dae4de31 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c @@ -137,7 +137,7 @@ static int inno_hdmi_rockchip_bind(struct device *dev, struct device *master, vo return ret; } - return drm_connector_attach_encoder(connector, encoder); + return 0; } static const struct component_ops inno_hdmi_rockchip_ops = { diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c index 54a0f124c7e1..1996f8656612 100644 --- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c +++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c @@ -731,8 +731,6 @@ rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi) return ret; } - drm_connector_attach_encoder(hdmi->connector, encoder); - return 0; } diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 75f898a10cbc..7a0c4fa29f2f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -628,12 +628,6 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, ret = PTR_ERR(connector); goto err_free_bridge; } - - ret = drm_connector_attach_encoder(connector, encoder); - if (ret < 0) { - drm_err(drm_dev, "failed to attach encoder: %d\n", ret); - goto err_free_bridge; - } } pm_runtime_enable(dev); diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c index 5c0c6e2cc28d..add3123e5ce7 100644 --- a/drivers/gpu/drm/rockchip/rockchip_rgb.c +++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c @@ -162,17 +162,8 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev, rgb->encoder.crtc_endpoint_id = endpoint_id; - ret = drm_connector_attach_encoder(connector, encoder); - if (ret < 0) { - DRM_DEV_ERROR(drm_dev->dev, - "failed to attach encoder: %d\n", ret); - goto err_free_connector; - } - return rgb; -err_free_connector: - drm_connector_cleanup(connector); err_free_encoder: drm_encoder_cleanup(encoder); return ERR_PTR(ret); diff --git a/drivers/gpu/drm/sysfb/corebootdrm.c b/drivers/gpu/drm/sysfb/corebootdrm.c index 5dc6f3c76f7b..853da9a609df 100644 --- a/drivers/gpu/drm/sysfb/corebootdrm.c +++ b/drivers/gpu/drm/sysfb/corebootdrm.c @@ -4,6 +4,7 @@ #include <linux/coreboot.h> #include <linux/minmax.h> #include <linux/platform_device.h> +#include <linux/pm.h> #include <drm/clients/drm_client_setup.h> #include <drm/drm_atomic.h> @@ -18,6 +19,7 @@ #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_gem_shmem_helper.h> #include <drm/drm_managed.h> +#include <drm/drm_modeset_helper.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> @@ -286,6 +288,24 @@ static struct drm_driver corebootdrm_drm_driver = { * Coreboot driver */ +static int corebootdrm_pm_suspend(struct device *dev) +{ + struct corebootdrm_device *cdev = dev_get_drvdata(dev); + struct drm_device *drm = &cdev->sysfb.dev; + + return drm_mode_config_helper_suspend(drm); +} + +static int corebootdrm_pm_resume(struct device *dev) +{ + struct corebootdrm_device *cdev = dev_get_drvdata(dev); + struct drm_device *drm = &cdev->sysfb.dev; + + return drm_mode_config_helper_resume(drm); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(corebootdrm_pm_ops, corebootdrm_pm_suspend, corebootdrm_pm_resume); + static int corebootdrm_probe(struct platform_device *pdev) { const struct lb_framebuffer *fb = dev_get_platdata(&pdev->dev); @@ -423,6 +443,7 @@ static void corebootdrm_remove(struct platform_device *pdev) static struct platform_driver corebootdrm_platform_driver = { .driver = { .name = "coreboot-framebuffer", + .pm = pm_sleep_ptr(&corebootdrm_pm_ops), }, .probe = corebootdrm_probe, .remove = corebootdrm_remove, diff --git a/drivers/gpu/drm/sysfb/efidrm.c b/drivers/gpu/drm/sysfb/efidrm.c index a335c94a7bd7..1a1e36700976 100644 --- a/drivers/gpu/drm/sysfb/efidrm.c +++ b/drivers/gpu/drm/sysfb/efidrm.c @@ -5,6 +5,7 @@ #include <linux/limits.h> #include <linux/platform_device.h> #include <linux/sysfb.h> +#include <linux/pm.h> #include <drm/clients/drm_client_setup.h> #include <drm/drm_atomic.h> @@ -20,6 +21,7 @@ #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_gem_shmem_helper.h> #include <drm/drm_managed.h> +#include <drm/drm_modeset_helper.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> @@ -371,6 +373,22 @@ static struct drm_driver efidrm_driver = { * Platform driver */ +static int efidrm_pm_suspend(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + + return drm_mode_config_helper_suspend(drm); +} + +static int efidrm_pm_resume(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + + return drm_mode_config_helper_resume(drm); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(efidrm_pm_ops, efidrm_pm_suspend, efidrm_pm_resume); + static int efidrm_probe(struct platform_device *pdev) { struct efidrm_device *efi; @@ -403,6 +421,7 @@ static void efidrm_remove(struct platform_device *pdev) static struct platform_driver efidrm_platform_driver = { .driver = { .name = "efi-framebuffer", + .pm = pm_sleep_ptr(&efidrm_pm_ops), }, .probe = efidrm_probe, .remove = efidrm_remove, diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c index 61c38bce8f64..819aed466727 100644 --- a/drivers/gpu/drm/sysfb/ofdrm.c +++ b/drivers/gpu/drm/sysfb/ofdrm.c @@ -4,6 +4,7 @@ #include <linux/of_address.h> #include <linux/pci.h> #include <linux/platform_device.h> +#include <linux/pm.h> #include <drm/clients/drm_client_setup.h> #include <drm/drm_atomic.h> @@ -20,6 +21,7 @@ #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_gem_shmem_helper.h> #include <drm/drm_managed.h> +#include <drm/drm_modeset_helper.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> @@ -1097,6 +1099,22 @@ static struct drm_driver ofdrm_driver = { * Platform driver */ +static int ofdrm_pm_suspend(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + + return drm_mode_config_helper_suspend(drm); +} + +static int ofdrm_pm_resume(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + + return drm_mode_config_helper_resume(drm); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(ofdrm_pm_ops, ofdrm_pm_suspend, ofdrm_pm_resume); + static int ofdrm_probe(struct platform_device *pdev) { struct ofdrm_device *odev; @@ -1136,6 +1154,7 @@ static struct platform_driver ofdrm_platform_driver = { .driver = { .name = "of-display", .of_match_table = ofdrm_of_match_display, + .pm = pm_sleep_ptr(&ofdrm_pm_ops), }, .probe = ofdrm_probe, .remove = ofdrm_remove, diff --git a/drivers/gpu/drm/sysfb/simpledrm.c b/drivers/gpu/drm/sysfb/simpledrm.c index 7a95d2dacd9d..fc168920f2c6 100644 --- a/drivers/gpu/drm/sysfb/simpledrm.c +++ b/drivers/gpu/drm/sysfb/simpledrm.c @@ -8,6 +8,7 @@ #include <linux/of_reserved_mem.h> #include <linux/platform_data/simplefb.h> #include <linux/platform_device.h> +#include <linux/pm.h> #include <linux/pm_domain.h> #include <linux/regulator/consumer.h> @@ -24,6 +25,7 @@ #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_gem_shmem_helper.h> #include <drm/drm_managed.h> +#include <drm/drm_modeset_helper.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> @@ -834,6 +836,24 @@ static struct drm_driver simpledrm_driver = { * Platform driver */ +static int simpledrm_pm_suspend(struct device *dev) +{ + struct simpledrm_device *sdev = dev_get_drvdata(dev); + struct drm_device *drm = &sdev->sysfb.dev; + + return drm_mode_config_helper_suspend(drm); +} + +static int simpledrm_pm_resume(struct device *dev) +{ + struct simpledrm_device *sdev = dev_get_drvdata(dev); + struct drm_device *drm = &sdev->sysfb.dev; + + return drm_mode_config_helper_resume(drm); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(simpledrm_pm_ops, simpledrm_pm_suspend, simpledrm_pm_resume); + static int simpledrm_probe(struct platform_device *pdev) { struct simpledrm_device *sdev; @@ -874,6 +894,7 @@ static struct platform_driver simpledrm_platform_driver = { .driver = { .name = "simple-framebuffer", /* connect to sysfb */ .of_match_table = simpledrm_of_match_table, + .pm = pm_sleep_ptr(&simpledrm_pm_ops), }, .probe = simpledrm_probe, .remove = simpledrm_remove, diff --git a/drivers/gpu/drm/sysfb/vesadrm.c b/drivers/gpu/drm/sysfb/vesadrm.c index dee3b4d6ec26..dbc317778d54 100644 --- a/drivers/gpu/drm/sysfb/vesadrm.c +++ b/drivers/gpu/drm/sysfb/vesadrm.c @@ -5,6 +5,7 @@ #include <linux/limits.h> #include <linux/platform_device.h> #include <linux/sysfb.h> +#include <linux/pm.h> #include <drm/clients/drm_client_setup.h> #include <drm/drm_atomic.h> @@ -21,6 +22,7 @@ #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_gem_shmem_helper.h> #include <drm/drm_managed.h> +#include <drm/drm_modeset_helper.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> @@ -617,6 +619,22 @@ static struct drm_driver vesadrm_driver = { * Platform driver */ +static int vesadrm_pm_suspend(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + + return drm_mode_config_helper_suspend(drm); +} + +static int vesadrm_pm_resume(struct device *dev) +{ + struct drm_device *drm = dev_get_drvdata(dev); + + return drm_mode_config_helper_resume(drm); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(vesadrm_pm_ops, vesadrm_pm_suspend, vesadrm_pm_resume); + static int vesadrm_probe(struct platform_device *pdev) { struct vesadrm_device *vesa; @@ -649,6 +667,7 @@ static void vesadrm_remove(struct platform_device *pdev) static struct platform_driver vesadrm_platform_driver = { .driver = { .name = "vesa-framebuffer", + .pm = pm_sleep_ptr(&vesadrm_pm_ops), }, .probe = vesadrm_probe, .remove = vesadrm_remove, diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 0adcd4244a42..10f02f35c866 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -1576,8 +1576,6 @@ static int tegra_hdmi_init(struct host1x_client *client) connector); return PTR_ERR(connector); } - - drm_connector_attach_encoder(connector, &hdmi->output.encoder); } else { drm_connector_init_with_ddc(drm, &hdmi->output.connector, &tegra_hdmi_connector_funcs, diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index ff5a749710db..e67fbb2362e6 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -355,8 +355,6 @@ int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc) connector); return PTR_ERR(connector); } - - drm_connector_attach_encoder(connector, &output->encoder); } err = tegra_output_init(drm, output); diff --git a/drivers/gpu/drm/tests/drm_bridge_test.c b/drivers/gpu/drm/tests/drm_bridge_test.c index 1f473d70e7e8..64b665580a88 100644 --- a/drivers/gpu/drm/tests/drm_bridge_test.c +++ b/drivers/gpu/drm/tests/drm_bridge_test.c @@ -173,8 +173,6 @@ drm_test_bridge_init(struct kunit *test, const struct drm_bridge_funcs *funcs) if (IS_ERR(priv->connector)) return ERR_CAST(priv->connector); - drm_connector_attach_encoder(priv->connector, enc); - drm_mode_config_reset(drm); return priv; diff --git a/drivers/gpu/drm/tidss/tidss_encoder.c b/drivers/gpu/drm/tidss/tidss_encoder.c index db467bbcdb77..34db8d2a3792 100644 --- a/drivers/gpu/drm/tidss/tidss_encoder.c +++ b/drivers/gpu/drm/tidss/tidss_encoder.c @@ -123,12 +123,6 @@ int tidss_encoder_create(struct tidss_device *tidss, return PTR_ERR(connector); } - ret = drm_connector_attach_encoder(connector, enc); - if (ret) { - dev_err(tidss->dev, "attaching encoder to connector failed\n"); - return ret; - } - t_enc->connector = connector; dev_dbg(tidss->dev, "Encoder create done\n"); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_encoder.c b/drivers/gpu/drm/tilcdc/tilcdc_encoder.c index 680a2ac6ab59..ac4b5beb2dd5 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_encoder.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_encoder.c @@ -35,12 +35,6 @@ int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge *bridge) return PTR_ERR(connector); } - ret = drm_connector_attach_encoder(connector, &priv->encoder->base); - if (ret) { - drm_err(ddev, "attaching encoder to connector failed\n"); - return ret; - } - priv->connector = connector; return 0; } diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c index a048e37f1c2c..562f3f11812a 100644 --- a/drivers/gpu/drm/tve200/tve200_drv.c +++ b/drivers/gpu/drm/tve200/tve200_drv.c @@ -221,12 +221,16 @@ static int tve200_probe(struct platform_device *pdev) ret = drm_dev_register(drm, 0); if (ret < 0) - goto clk_disable; + goto mode_config_cleanup; drm_client_setup_with_fourcc(drm, DRM_FORMAT_RGB565); return 0; +mode_config_cleanup: + if (priv->panel) + drm_panel_bridge_remove(priv->bridge); + drm_mode_config_cleanup(drm); clk_disable: clk_disable_unprepare(priv->pclk); dev_unref: diff --git a/drivers/gpu/drm/verisilicon/vs_bridge.c b/drivers/gpu/drm/verisilicon/vs_bridge.c index 17add75b8878..7a93049368db 100644 --- a/drivers/gpu/drm/verisilicon/vs_bridge.c +++ b/drivers/gpu/drm/verisilicon/vs_bridge.c @@ -365,7 +365,6 @@ struct vs_bridge *vs_bridge_init(struct drm_device *drm_dev, ret = PTR_ERR(bridge->conn); return ERR_PTR(ret); } - drm_connector_attach_encoder(bridge->conn, bridge->enc); return bridge; } diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c index 2f3953e588a3..d81f7b8f4c65 100644 --- a/drivers/gpu/drm/verisilicon/vs_plane.c +++ b/drivers/gpu/drm/verisilicon/vs_plane.c @@ -6,13 +6,15 @@ #include <linux/errno.h> #include <linux/printk.h> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_gem_dma_helper.h> +#include <drm/drm_print.h> #include "vs_plane.h" -void drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format) +int drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format) { switch (drm_format) { case DRM_FORMAT_XRGB4444: @@ -62,7 +64,7 @@ void drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format) vs_format->color = VSDC_COLOR_FORMAT_A2R10G10B10; break; default: - pr_warn("Unexpected drm format!\n"); + return -EINVAL; } switch (drm_format) { @@ -101,6 +103,8 @@ void drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format) /* N/A for non-YUV formats */ vs_format->uv_swizzle = false; + + return 0; } dma_addr_t vs_fb_get_dma_addr(struct drm_framebuffer *fb, @@ -122,3 +126,49 @@ dma_addr_t vs_fb_get_dma_addr(struct drm_framebuffer *fb, return dma_addr; } + +struct drm_plane_state *vs_plane_duplicate_state(struct drm_plane *plane) +{ + struct vs_plane_state *vs_state, *vs_state_old; + + if (drm_WARN_ON(plane->dev, !plane->state)) + return NULL; + + vs_state_old = to_vs_plane_state(plane->state); + + vs_state = kzalloc_obj(*vs_state, GFP_KERNEL); + if (!vs_state) + return NULL; + + __drm_atomic_helper_plane_duplicate_state(plane, &vs_state->base); + + memcpy(&vs_state->format, &vs_state_old->format, + sizeof(struct vs_format)); + + return &vs_state->base; +} + +void vs_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + __drm_atomic_helper_plane_destroy_state(state); + kfree(state); +} + +/* Called during init to allocate the plane's atomic state. */ +void vs_plane_reset(struct drm_plane *plane) +{ + struct vs_plane_state *vs_state; + + if (plane->state) { + __drm_atomic_helper_plane_destroy_state(plane->state); + kfree(plane->state); + plane->state = NULL; + } + + vs_state = kzalloc_obj(*vs_state, GFP_KERNEL); + if (!vs_state) + return; + + __drm_atomic_helper_plane_reset(plane, &vs_state->base); +} diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h b/drivers/gpu/drm/verisilicon/vs_plane.h index 41875ea3d66a..f18c36ef4cd9 100644 --- a/drivers/gpu/drm/verisilicon/vs_plane.h +++ b/drivers/gpu/drm/verisilicon/vs_plane.h @@ -63,10 +63,26 @@ struct vs_format { bool uv_swizzle; }; -void drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format); +struct vs_plane_state { + struct drm_plane_state base; + + struct vs_format format; +}; + +static inline struct vs_plane_state *to_vs_plane_state(struct drm_plane_state *state) +{ + return container_of(state, struct vs_plane_state, base); +} + +int drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format); dma_addr_t vs_fb_get_dma_addr(struct drm_framebuffer *fb, const struct drm_rect *src_rect); +struct drm_plane_state *vs_plane_duplicate_state(struct drm_plane *plane); +void vs_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state); +void vs_plane_reset(struct drm_plane *plane); + struct drm_plane *vs_primary_plane_init(struct drm_device *dev, struct vs_dc *dc); #endif /* _VS_PLANE_H_ */ diff --git a/drivers/gpu/drm/verisilicon/vs_primary_plane.c b/drivers/gpu/drm/verisilicon/vs_primary_plane.c index f3bf18c0e168..1f2be41ae496 100644 --- a/drivers/gpu/drm/verisilicon/vs_primary_plane.c +++ b/drivers/gpu/drm/verisilicon/vs_primary_plane.c @@ -25,21 +25,32 @@ static int vs_primary_plane_atomic_check(struct drm_plane *plane, { struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); + struct vs_plane_state *new_vs_plane_state = to_vs_plane_state(new_plane_state); + struct drm_framebuffer *fb = new_plane_state->fb; struct drm_crtc *crtc = new_plane_state->crtc; - struct drm_crtc_state *crtc_state; + struct drm_crtc_state *crtc_state = NULL; + int ret; - if (!crtc) + if (crtc) + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + + ret = drm_atomic_helper_check_plane_state(new_plane_state, + crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, true); + if (ret) + return ret; + + if (!new_plane_state->visible) return 0; - crtc_state = drm_atomic_get_new_crtc_state(state, crtc); - if (WARN_ON(!crtc_state)) - return -EINVAL; + ret = drm_format_to_vs_format(fb->format->format, + &new_vs_plane_state->format); + if (drm_WARN_ON_ONCE(plane->dev, ret)) + return ret; - return drm_atomic_helper_check_plane_state(new_plane_state, - crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - false, true); + return 0; } static void vs_primary_plane_commit(struct vs_dc *dc, unsigned int output) @@ -88,11 +99,11 @@ static void vs_primary_plane_atomic_update(struct drm_plane *plane, { struct drm_plane_state *state = drm_atomic_get_new_plane_state(atomic_state, plane); + struct vs_plane_state *vs_state = to_vs_plane_state(state); struct drm_framebuffer *fb = state->fb; struct drm_crtc *crtc = state->crtc; struct vs_dc *dc; struct vs_crtc *vcrtc; - struct vs_format fmt; unsigned int output; dma_addr_t dma_addr; @@ -105,16 +116,15 @@ static void vs_primary_plane_atomic_update(struct drm_plane *plane, output = vcrtc->id; dc = vcrtc->dc; - drm_format_to_vs_format(state->fb->format->format, &fmt); - regmap_update_bits(dc->regs, VSDC_FB_CONFIG(output), VSDC_FB_CONFIG_FMT_MASK, - VSDC_FB_CONFIG_FMT(fmt.color)); + VSDC_FB_CONFIG_FMT(vs_state->format.color)); regmap_update_bits(dc->regs, VSDC_FB_CONFIG(output), VSDC_FB_CONFIG_SWIZZLE_MASK, - VSDC_FB_CONFIG_SWIZZLE(fmt.swizzle)); + VSDC_FB_CONFIG_SWIZZLE(vs_state->format.swizzle)); regmap_assign_bits(dc->regs, VSDC_FB_CONFIG(output), - VSDC_FB_CONFIG_UV_SWIZZLE_EN, fmt.uv_swizzle); + VSDC_FB_CONFIG_UV_SWIZZLE_EN, + vs_state->format.uv_swizzle); dma_addr = vs_fb_get_dma_addr(fb, &state->src); @@ -145,10 +155,10 @@ static const struct drm_plane_helper_funcs vs_primary_plane_helper_funcs = { }; static const struct drm_plane_funcs vs_primary_plane_funcs = { - .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, - .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = vs_plane_destroy_state, + .atomic_duplicate_state = vs_plane_duplicate_state, .disable_plane = drm_atomic_helper_disable_plane, - .reset = drm_atomic_helper_plane_reset, + .reset = vs_plane_reset, .update_plane = drm_atomic_helper_update_plane, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 1b05dde2bef3..2224d7d91d1b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -322,8 +322,6 @@ struct vmw_display_unit { struct { struct work_struct crc_generator_work; - struct hrtimer timer; - ktime_t period_ns; /* protects concurrent access to the vblank handler */ atomic_t atomic_lock; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index cd32b5e35199..af3e32174563 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -402,6 +402,7 @@ static const struct drm_crtc_helper_funcs vmw_ldu_crtc_helper_funcs = { .atomic_flush = vmw_vkms_crtc_atomic_flush, .atomic_enable = vmw_vkms_crtc_atomic_enable, .atomic_disable = vmw_vkms_crtc_atomic_disable, + .handle_vblank_timeout = vmw_vkms_handle_vblank_timeout, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index b6148e437175..c83061cf7455 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -797,6 +797,7 @@ static const struct drm_crtc_helper_funcs vmw_sou_crtc_helper_funcs = { .atomic_flush = vmw_vkms_crtc_atomic_flush, .atomic_enable = vmw_vkms_crtc_atomic_enable, .atomic_disable = vmw_sou_crtc_atomic_disable, + .handle_vblank_timeout = vmw_vkms_handle_vblank_timeout, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 353495739c03..4139837f4caf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1515,6 +1515,7 @@ static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = { .atomic_flush = vmw_stdu_crtc_atomic_flush, .atomic_enable = vmw_vkms_crtc_atomic_enable, .atomic_disable = vmw_stdu_crtc_atomic_disable, + .handle_vblank_timeout = vmw_vkms_handle_vblank_timeout, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c index 1c59dec4c769..7b8163b5e501 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c @@ -157,27 +157,19 @@ crc_generate_worker(struct work_struct *work) drm_crtc_add_crc_entry(crtc, true, frame_start++, &crc32); } -static enum hrtimer_restart -vmw_vkms_vblank_simulate(struct hrtimer *timer) +bool +vmw_vkms_handle_vblank_timeout(struct drm_crtc *crtc) { - struct vmw_display_unit *du = container_of(timer, struct vmw_display_unit, vkms.timer); - struct drm_crtc *crtc = &du->crtc; + struct vmw_display_unit *du = vmw_crtc_to_du(crtc); struct vmw_private *vmw = vmw_priv(crtc->dev); bool has_surface = false; - u64 ret_overrun; bool locked, ret; - ret_overrun = hrtimer_forward_now(&du->vkms.timer, - du->vkms.period_ns); - if (ret_overrun != 1) - drm_dbg_driver(crtc->dev, "vblank timer missed %lld frames.\n", - ret_overrun - 1); - locked = vmw_vkms_vblank_trylock(crtc); ret = drm_crtc_handle_vblank(crtc); WARN_ON(!ret); if (!locked) - return HRTIMER_RESTART; + return true; has_surface = du->vkms.surface != NULL; vmw_vkms_unlock(crtc); @@ -200,7 +192,7 @@ vmw_vkms_vblank_simulate(struct hrtimer *timer) drm_dbg_driver(crtc->dev, "Composer worker already queued\n"); } - return HRTIMER_RESTART; + return true; } void @@ -245,32 +237,12 @@ vmw_vkms_get_vblank_timestamp(struct drm_crtc *crtc, ktime_t *vblank_time, bool in_vblank_irq) { - struct drm_device *dev = crtc->dev; - struct vmw_private *vmw = vmw_priv(dev); - struct vmw_display_unit *du = vmw_crtc_to_du(crtc); - struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); + struct vmw_private *vmw = vmw_priv(crtc->dev); if (!vmw->vkms_enabled) return false; - if (!READ_ONCE(vblank->enabled)) { - *vblank_time = ktime_get(); - return true; - } - - *vblank_time = READ_ONCE(du->vkms.timer.node.expires); - - if (WARN_ON(*vblank_time == vblank->time)) - return true; - - /* - * To prevent races we roll the hrtimer forward before we do any - * interrupt processing - this is how real hw works (the interrupt is - * only generated after all the vblank registers are updated) and what - * the vblank core expects. Therefore we need to always correct the - * timestampe by one frame. - */ - *vblank_time -= du->vkms.period_ns; + drm_crtc_vblank_get_vblank_timeout(crtc, vblank_time); return true; } @@ -280,20 +252,11 @@ vmw_vkms_enable_vblank(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct vmw_private *vmw = vmw_priv(dev); - struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); - struct vmw_display_unit *du = vmw_crtc_to_du(crtc); if (!vmw->vkms_enabled) return -EINVAL; - drm_calc_timestamping_constants(crtc, &crtc->mode); - - hrtimer_setup(&du->vkms.timer, &vmw_vkms_vblank_simulate, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - du->vkms.period_ns = ktime_set(0, vblank->framedur_ns); - hrtimer_start(&du->vkms.timer, du->vkms.period_ns, HRTIMER_MODE_REL); - - return 0; + return drm_crtc_vblank_start_timer(crtc); } void @@ -305,9 +268,9 @@ vmw_vkms_disable_vblank(struct drm_crtc *crtc) if (!vmw->vkms_enabled) return; - hrtimer_cancel(&du->vkms.timer); + drm_crtc_vblank_cancel_timer(crtc); + du->vkms.surface = NULL; - du->vkms.period_ns = ktime_set(0, 0); } enum vmw_vkms_lock_state { @@ -331,12 +294,15 @@ vmw_vkms_crtc_init(struct drm_crtc *crtc) void vmw_vkms_crtc_cleanup(struct drm_crtc *crtc) { + struct vmw_private *vmw = vmw_priv(crtc->dev); struct vmw_display_unit *du = vmw_crtc_to_du(crtc); + if (vmw->vkms_enabled) + drm_crtc_vblank_cancel_timer(crtc); + if (du->vkms.surface) vmw_surface_unreference(&du->vkms.surface); WARN_ON(work_pending(&du->vkms.crc_generator_work)); - hrtimer_cancel(&du->vkms.timer); } void @@ -516,9 +482,13 @@ vmw_vkms_set_crc_surface(struct drm_crtc *crtc, static inline u64 vmw_vkms_lock_max_wait_ns(struct vmw_display_unit *du) { - s64 nsecs = ktime_to_ns(du->vkms.period_ns); + struct drm_crtc *crtc = &du->crtc; + struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); + + if (!vblank || !vblank->framedur_ns) + return NSEC_PER_SEC / 60; /* disabled; assume 60 Hz */ - return (nsecs > 0) ? nsecs : 16666666; + return vblank->framedur_ns; } /** diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h index 825b31bf8d39..27bc846313ca 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h @@ -29,7 +29,6 @@ #ifndef VMWGFX_VKMS_H_ #define VMWGFX_VKMS_H_ -#include <linux/hrtimer_types.h> #include <linux/types.h> struct drm_atomic_commit; @@ -45,6 +44,7 @@ bool vmw_vkms_modeset_lock_relaxed(struct drm_crtc *crtc); bool vmw_vkms_vblank_trylock(struct drm_crtc *crtc); void vmw_vkms_unlock(struct drm_crtc *crtc); +bool vmw_vkms_handle_vblank_timeout(struct drm_crtc *crtc); bool vmw_vkms_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error, ktime_t *vblank_time, diff --git a/drivers/gpu/drm/xe/xe_sync.c b/drivers/gpu/drm/xe/xe_sync.c index 24d6d9af20d6..37866768d64c 100644 --- a/drivers/gpu/drm/xe/xe_sync.c +++ b/drivers/gpu/drm/xe/xe_sync.c @@ -376,7 +376,7 @@ xe_sync_in_fence_get(struct xe_sync_entry *sync, int num_sync, xe_assert(vm->xe, current_fence == num_fence); cf = dma_fence_array_create(num_fence, fences, dma_fence_context_alloc(1), - 1, false); + 1); if (!cf) goto err_out; diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index c3836f6eab35..43a578d9c067 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -3414,7 +3414,7 @@ collect_fences: xe_assert(vm->xe, current_fence == n_fence); dma_fence_array_init(cf, n_fence, fences, dma_fence_context_alloc(1), - 1, false); + 1); fence = &cf->base; for_each_tile(tile, vm->xe, id) { diff --git a/drivers/gpu/drm/xlnx/Kconfig b/drivers/gpu/drm/xlnx/Kconfig index cfabf5e2a0bb..58c19e5a7e8f 100644 --- a/drivers/gpu/drm/xlnx/Kconfig +++ b/drivers/gpu/drm/xlnx/Kconfig @@ -3,8 +3,8 @@ config DRM_ZYNQMP_DPSUB depends on ARCH_ZYNQMP || COMPILE_TEST depends on COMMON_CLK && DRM && OF depends on DMADEVICES - depends on PHY_XILINX_ZYNQMP - depends on XILINX_ZYNQMP_DPDMA + depends on PHY_XILINX_ZYNQMP || COMPILE_TEST + depends on XILINX_ZYNQMP_DPDMA || COMPILE_TEST select DMA_ENGINE select DRM_CLIENT_SELECTION select DRM_DISPLAY_DP_HELPER diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index 9a8f38230cb4..52a0712e39c4 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -297,6 +297,36 @@ static const struct zynqmp_disp_format avbuf_vid_fmts[] = { .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420, .swap = true, .sf = scaling_factors_888, + }, { + .drm_fmt = DRM_FORMAT_P030, + .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420_10, + .swap = false, + .sf = scaling_factors_101010, + }, { + .drm_fmt = DRM_FORMAT_P230, + .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_10, + .swap = false, + .sf = scaling_factors_101010, + }, { + .drm_fmt = DRM_FORMAT_Y8, + .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MONO, + .swap = false, + .sf = scaling_factors_888, + }, { + .drm_fmt = DRM_FORMAT_XYYY2101010, + .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YONLY_10, + .swap = false, + .sf = scaling_factors_101010, + }, { + .drm_fmt = DRM_FORMAT_T430, + .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV24_10, + .swap = false, + .sf = scaling_factors_101010, + }, { + .drm_fmt = DRM_FORMAT_XVUY2101010, + .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YUV444_10, + .swap = false, + .sf = scaling_factors_101010, }, }; @@ -687,6 +717,17 @@ static const u32 csc_sdtv_to_rgb_offsets[] = { 0x0, 0x1800, 0x1800 }; +/* In Y-only mode the single Y channel is on the third column */ +static const u16 csc_sdtv_to_rgb_yonly_matrix[] = { + 0x0, 0x0, 0x1000, + 0x0, 0x0, 0x1000, + 0x0, 0x0, 0x1000, +}; + +static const u32 csc_sdtv_to_rgb_yonly_offsets[] = { + 0x0, 0x0, 0x0 +}; + /** * zynqmp_disp_blend_set_output_format - Set the output format of the blender * @disp: Display controller @@ -836,7 +877,11 @@ static void zynqmp_disp_blend_layer_enable(struct zynqmp_disp *disp, ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id), val); - if (layer->drm_fmt->is_yuv) { + if (layer->drm_fmt->format == DRM_FORMAT_Y8 || + layer->drm_fmt->format == DRM_FORMAT_XYYY2101010) { + coeffs = csc_sdtv_to_rgb_yonly_matrix; + offsets = csc_sdtv_to_rgb_yonly_offsets; + } else if (layer->drm_fmt->is_yuv) { coeffs = csc_sdtv_to_rgb_matrix; offsets = csc_sdtv_to_rgb_offsets; } else { @@ -1116,16 +1161,19 @@ int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer, return 0; for (i = 0; i < info->num_planes; i++) { - unsigned int width = state->crtc_w / (i ? info->hsub : 1); - unsigned int height = state->crtc_h / (i ? info->vsub : 1); struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; struct dma_async_tx_descriptor *desc; dma_addr_t dma_addr; + unsigned int width; + unsigned int height; + + width = drm_format_info_plane_width(info, state->crtc_w, i); + height = drm_format_info_plane_height(info, state->crtc_h, i); dma_addr = drm_fb_dma_get_gem_addr(state->fb, state, i); dma->xt.numf = height; - dma->sgl.size = width * info->cpp[i]; + dma->sgl.size = drm_format_info_min_pitch(info, i, width); dma->sgl.icg = state->fb->pitches[i] - dma->sgl.size; dma->xt.src_start = dma_addr; dma->xt.frame_size = 1; diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c index dcb2fff54b63..d5f922450565 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_kms.c +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c @@ -453,12 +453,6 @@ static int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub) goto err_encoder; } - ret = drm_connector_attach_encoder(connector, encoder); - if (ret < 0) { - dev_err(dpsub->dev, "failed to attach connector to encoder\n"); - goto err_encoder; - } - return 0; err_encoder: |
