| From 1211fb5c348a9536dfe31edf9ea7a0620a2bd0c4 Mon Sep 17 00:00:00 2001 |
| From: Neil Armstrong <narmstrong@baylibre.com> |
| Date: Fri, 3 Mar 2017 19:20:06 +0200 |
| Subject: [PATCH 233/286] drm: bridge: dw-hdmi: Switch to regmap for register |
| access |
| |
| The Synopsys Designware HDMI TX Controller does not enforce register |
| access on platforms instanciating it. The current driver supports two |
| different types of memory-mapped flat register access, but in order to |
| support the Amlogic Meson SoCs integration, and provide a more generic |
| way to handle all sorts of register mapping, switch the register access |
| to use the regmap infrastructure. |
| |
| In the case of registers that are not flat memory-mapped or do not |
| conform to the current driver implementation, a regmap struct can be |
| given in the plat_data and be used at probe or bind. |
| |
| Since the AHB audio driver is only available with direct memory access, |
| only allow the I2S audio driver to be registered is directly |
| memory-mapped. |
| |
| Signed-off-by: Neil Armstrong <narmstrong@baylibre.com> |
| Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> |
| Tested-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> |
| Tested-by: Neil Armstrong <narmstrong@baylibre.com> |
| Reviewed-by: Jose Abreu <Jose.Abreu@synopsys.com> |
| Signed-off-by: Archit Taneja <architt@codeaurora.org> |
| Link: http://patchwork.freedesktop.org/patch/msgid/20170303172007.26541-10-laurent.pinchart+renesas@ideasonboard.com |
| (cherry picked from commit 80e2f97968b537fc9c1789fce1b7f61609a5aae4) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/gpu/drm/bridge/dw-hdmi.c | 109 ++++++++++++++++++++------------------- |
| include/drm/bridge/dw_hdmi.h | 1 |
| 2 files changed, 59 insertions(+), 51 deletions(-) |
| |
| --- a/drivers/gpu/drm/bridge/dw-hdmi.c |
| +++ b/drivers/gpu/drm/bridge/dw-hdmi.c |
| @@ -19,6 +19,7 @@ |
| #include <linux/hdmi.h> |
| #include <linux/mutex.h> |
| #include <linux/of_device.h> |
| +#include <linux/regmap.h> |
| #include <linux/spinlock.h> |
| |
| #include <drm/drm_of.h> |
| @@ -171,8 +172,8 @@ struct dw_hdmi { |
| unsigned int audio_n; |
| bool audio_enable; |
| |
| - void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); |
| - u8 (*read)(struct dw_hdmi *hdmi, int offset); |
| + unsigned int reg_shift; |
| + struct regmap *regm; |
| }; |
| |
| #define HDMI_IH_PHY_STAT0_RX_SENSE \ |
| @@ -183,42 +184,23 @@ struct dw_hdmi { |
| (HDMI_PHY_RX_SENSE0 | HDMI_PHY_RX_SENSE1 | \ |
| HDMI_PHY_RX_SENSE2 | HDMI_PHY_RX_SENSE3) |
| |
| -static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset) |
| -{ |
| - writel(val, hdmi->regs + (offset << 2)); |
| -} |
| - |
| -static u8 dw_hdmi_readl(struct dw_hdmi *hdmi, int offset) |
| -{ |
| - return readl(hdmi->regs + (offset << 2)); |
| -} |
| - |
| -static void dw_hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset) |
| -{ |
| - writeb(val, hdmi->regs + offset); |
| -} |
| - |
| -static u8 dw_hdmi_readb(struct dw_hdmi *hdmi, int offset) |
| -{ |
| - return readb(hdmi->regs + offset); |
| -} |
| - |
| static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset) |
| { |
| - hdmi->write(hdmi, val, offset); |
| + regmap_write(hdmi->regm, offset << hdmi->reg_shift, val); |
| } |
| |
| static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset) |
| { |
| - return hdmi->read(hdmi, offset); |
| + unsigned int val = 0; |
| + |
| + regmap_read(hdmi->regm, offset << hdmi->reg_shift, &val); |
| + |
| + return val; |
| } |
| |
| static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg) |
| { |
| - u8 val = hdmi_readb(hdmi, reg) & ~mask; |
| - |
| - val |= data & mask; |
| - hdmi_writeb(hdmi, val, reg); |
| + regmap_update_bits(hdmi->regm, reg << hdmi->reg_shift, mask, data); |
| } |
| |
| static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg, |
| @@ -1989,6 +1971,20 @@ static int dw_hdmi_detect_phy(struct dw_ |
| return -ENODEV; |
| } |
| |
| +static const struct regmap_config hdmi_regmap_8bit_config = { |
| + .reg_bits = 32, |
| + .val_bits = 8, |
| + .reg_stride = 1, |
| + .max_register = HDMI_I2CM_FS_SCL_LCNT_0_ADDR, |
| +}; |
| + |
| +static const struct regmap_config hdmi_regmap_32bit_config = { |
| + .reg_bits = 32, |
| + .val_bits = 32, |
| + .reg_stride = 4, |
| + .max_register = HDMI_I2CM_FS_SCL_LCNT_0_ADDR << 2, |
| +}; |
| + |
| static struct dw_hdmi * |
| __dw_hdmi_probe(struct platform_device *pdev, |
| const struct dw_hdmi_plat_data *plat_data) |
| @@ -1998,7 +1994,7 @@ __dw_hdmi_probe(struct platform_device * |
| struct platform_device_info pdevinfo; |
| struct device_node *ddc_node; |
| struct dw_hdmi *hdmi; |
| - struct resource *iores; |
| + struct resource *iores = NULL; |
| int irq; |
| int ret; |
| u32 val = 1; |
| @@ -2022,22 +2018,6 @@ __dw_hdmi_probe(struct platform_device * |
| mutex_init(&hdmi->audio_mutex); |
| spin_lock_init(&hdmi->audio_lock); |
| |
| - of_property_read_u32(np, "reg-io-width", &val); |
| - |
| - switch (val) { |
| - case 4: |
| - hdmi->write = dw_hdmi_writel; |
| - hdmi->read = dw_hdmi_readl; |
| - break; |
| - case 1: |
| - hdmi->write = dw_hdmi_writeb; |
| - hdmi->read = dw_hdmi_readb; |
| - break; |
| - default: |
| - dev_err(dev, "reg-io-width must be 1 or 4\n"); |
| - return ERR_PTR(-EINVAL); |
| - } |
| - |
| ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); |
| if (ddc_node) { |
| hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node); |
| @@ -2051,11 +2031,38 @@ __dw_hdmi_probe(struct platform_device * |
| dev_dbg(hdmi->dev, "no ddc property found\n"); |
| } |
| |
| - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| - hdmi->regs = devm_ioremap_resource(dev, iores); |
| - if (IS_ERR(hdmi->regs)) { |
| - ret = PTR_ERR(hdmi->regs); |
| - goto err_res; |
| + if (!plat_data->regm) { |
| + const struct regmap_config *reg_config; |
| + |
| + of_property_read_u32(np, "reg-io-width", &val); |
| + switch (val) { |
| + case 4: |
| + reg_config = &hdmi_regmap_32bit_config; |
| + hdmi->reg_shift = 2; |
| + break; |
| + case 1: |
| + reg_config = &hdmi_regmap_8bit_config; |
| + break; |
| + default: |
| + dev_err(dev, "reg-io-width must be 1 or 4\n"); |
| + return ERR_PTR(-EINVAL); |
| + } |
| + |
| + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| + hdmi->regs = devm_ioremap_resource(dev, iores); |
| + if (IS_ERR(hdmi->regs)) { |
| + ret = PTR_ERR(hdmi->regs); |
| + goto err_res; |
| + } |
| + |
| + hdmi->regm = devm_regmap_init_mmio(dev, hdmi->regs, reg_config); |
| + if (IS_ERR(hdmi->regm)) { |
| + dev_err(dev, "Failed to configure regmap\n"); |
| + ret = PTR_ERR(hdmi->regm); |
| + goto err_res; |
| + } |
| + } else { |
| + hdmi->regm = plat_data->regm; |
| } |
| |
| hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr"); |
| @@ -2165,7 +2172,7 @@ __dw_hdmi_probe(struct platform_device * |
| config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID); |
| config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID); |
| |
| - if (config3 & HDMI_CONFIG3_AHBAUDDMA) { |
| + if (iores && config3 & HDMI_CONFIG3_AHBAUDDMA) { |
| struct dw_hdmi_audio_data audio; |
| |
| audio.phys = iores->start; |
| --- a/include/drm/bridge/dw_hdmi.h |
| +++ b/include/drm/bridge/dw_hdmi.h |
| @@ -59,6 +59,7 @@ struct dw_hdmi_phy_ops { |
| }; |
| |
| struct dw_hdmi_plat_data { |
| + struct regmap *regm; |
| enum drm_mode_status (*mode_valid)(struct drm_connector *connector, |
| struct drm_display_mode *mode); |
| |