diff options
-rw-r--r-- | drivers/gpu/drm/bridge/dw-hdmi.c | 109 | ||||
-rw-r--r-- | include/drm/bridge/dw_hdmi.h | 1 |
2 files changed, 59 insertions, 51 deletions
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 132c00685796..026a0dce7661 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/hdmi.h> | 19 | #include <linux/hdmi.h> |
20 | #include <linux/mutex.h> | 20 | #include <linux/mutex.h> |
21 | #include <linux/of_device.h> | 21 | #include <linux/of_device.h> |
22 | #include <linux/regmap.h> | ||
22 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
23 | 24 | ||
24 | #include <drm/drm_of.h> | 25 | #include <drm/drm_of.h> |
@@ -171,8 +172,8 @@ struct dw_hdmi { | |||
171 | unsigned int audio_n; | 172 | unsigned int audio_n; |
172 | bool audio_enable; | 173 | bool audio_enable; |
173 | 174 | ||
174 | void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); | 175 | unsigned int reg_shift; |
175 | u8 (*read)(struct dw_hdmi *hdmi, int offset); | 176 | struct regmap *regm; |
176 | }; | 177 | }; |
177 | 178 | ||
178 | #define HDMI_IH_PHY_STAT0_RX_SENSE \ | 179 | #define HDMI_IH_PHY_STAT0_RX_SENSE \ |
@@ -183,42 +184,23 @@ struct dw_hdmi { | |||
183 | (HDMI_PHY_RX_SENSE0 | HDMI_PHY_RX_SENSE1 | \ | 184 | (HDMI_PHY_RX_SENSE0 | HDMI_PHY_RX_SENSE1 | \ |
184 | HDMI_PHY_RX_SENSE2 | HDMI_PHY_RX_SENSE3) | 185 | HDMI_PHY_RX_SENSE2 | HDMI_PHY_RX_SENSE3) |
185 | 186 | ||
186 | static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset) | ||
187 | { | ||
188 | writel(val, hdmi->regs + (offset << 2)); | ||
189 | } | ||
190 | |||
191 | static u8 dw_hdmi_readl(struct dw_hdmi *hdmi, int offset) | ||
192 | { | ||
193 | return readl(hdmi->regs + (offset << 2)); | ||
194 | } | ||
195 | |||
196 | static void dw_hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset) | ||
197 | { | ||
198 | writeb(val, hdmi->regs + offset); | ||
199 | } | ||
200 | |||
201 | static u8 dw_hdmi_readb(struct dw_hdmi *hdmi, int offset) | ||
202 | { | ||
203 | return readb(hdmi->regs + offset); | ||
204 | } | ||
205 | |||
206 | static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset) | 187 | static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset) |
207 | { | 188 | { |
208 | hdmi->write(hdmi, val, offset); | 189 | regmap_write(hdmi->regm, offset << hdmi->reg_shift, val); |
209 | } | 190 | } |
210 | 191 | ||
211 | static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset) | 192 | static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset) |
212 | { | 193 | { |
213 | return hdmi->read(hdmi, offset); | 194 | unsigned int val = 0; |
195 | |||
196 | regmap_read(hdmi->regm, offset << hdmi->reg_shift, &val); | ||
197 | |||
198 | return val; | ||
214 | } | 199 | } |
215 | 200 | ||
216 | static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg) | 201 | static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg) |
217 | { | 202 | { |
218 | u8 val = hdmi_readb(hdmi, reg) & ~mask; | 203 | regmap_update_bits(hdmi->regm, reg << hdmi->reg_shift, mask, data); |
219 | |||
220 | val |= data & mask; | ||
221 | hdmi_writeb(hdmi, val, reg); | ||
222 | } | 204 | } |
223 | 205 | ||
224 | static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg, | 206 | 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_hdmi *hdmi) | |||
1989 | return -ENODEV; | 1971 | return -ENODEV; |
1990 | } | 1972 | } |
1991 | 1973 | ||
1974 | static const struct regmap_config hdmi_regmap_8bit_config = { | ||
1975 | .reg_bits = 32, | ||
1976 | .val_bits = 8, | ||
1977 | .reg_stride = 1, | ||
1978 | .max_register = HDMI_I2CM_FS_SCL_LCNT_0_ADDR, | ||
1979 | }; | ||
1980 | |||
1981 | static const struct regmap_config hdmi_regmap_32bit_config = { | ||
1982 | .reg_bits = 32, | ||
1983 | .val_bits = 32, | ||
1984 | .reg_stride = 4, | ||
1985 | .max_register = HDMI_I2CM_FS_SCL_LCNT_0_ADDR << 2, | ||
1986 | }; | ||
1987 | |||
1992 | static struct dw_hdmi * | 1988 | static struct dw_hdmi * |
1993 | __dw_hdmi_probe(struct platform_device *pdev, | 1989 | __dw_hdmi_probe(struct platform_device *pdev, |
1994 | const struct dw_hdmi_plat_data *plat_data) | 1990 | const struct dw_hdmi_plat_data *plat_data) |
@@ -1998,7 +1994,7 @@ __dw_hdmi_probe(struct platform_device *pdev, | |||
1998 | struct platform_device_info pdevinfo; | 1994 | struct platform_device_info pdevinfo; |
1999 | struct device_node *ddc_node; | 1995 | struct device_node *ddc_node; |
2000 | struct dw_hdmi *hdmi; | 1996 | struct dw_hdmi *hdmi; |
2001 | struct resource *iores; | 1997 | struct resource *iores = NULL; |
2002 | int irq; | 1998 | int irq; |
2003 | int ret; | 1999 | int ret; |
2004 | u32 val = 1; | 2000 | u32 val = 1; |
@@ -2022,22 +2018,6 @@ __dw_hdmi_probe(struct platform_device *pdev, | |||
2022 | mutex_init(&hdmi->audio_mutex); | 2018 | mutex_init(&hdmi->audio_mutex); |
2023 | spin_lock_init(&hdmi->audio_lock); | 2019 | spin_lock_init(&hdmi->audio_lock); |
2024 | 2020 | ||
2025 | of_property_read_u32(np, "reg-io-width", &val); | ||
2026 | |||
2027 | switch (val) { | ||
2028 | case 4: | ||
2029 | hdmi->write = dw_hdmi_writel; | ||
2030 | hdmi->read = dw_hdmi_readl; | ||
2031 | break; | ||
2032 | case 1: | ||
2033 | hdmi->write = dw_hdmi_writeb; | ||
2034 | hdmi->read = dw_hdmi_readb; | ||
2035 | break; | ||
2036 | default: | ||
2037 | dev_err(dev, "reg-io-width must be 1 or 4\n"); | ||
2038 | return ERR_PTR(-EINVAL); | ||
2039 | } | ||
2040 | |||
2041 | ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); | 2021 | ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); |
2042 | if (ddc_node) { | 2022 | if (ddc_node) { |
2043 | hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node); | 2023 | hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node); |
@@ -2051,11 +2031,38 @@ __dw_hdmi_probe(struct platform_device *pdev, | |||
2051 | dev_dbg(hdmi->dev, "no ddc property found\n"); | 2031 | dev_dbg(hdmi->dev, "no ddc property found\n"); |
2052 | } | 2032 | } |
2053 | 2033 | ||
2054 | iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 2034 | if (!plat_data->regm) { |
2055 | hdmi->regs = devm_ioremap_resource(dev, iores); | 2035 | const struct regmap_config *reg_config; |
2056 | if (IS_ERR(hdmi->regs)) { | 2036 | |
2057 | ret = PTR_ERR(hdmi->regs); | 2037 | of_property_read_u32(np, "reg-io-width", &val); |
2058 | goto err_res; | 2038 | switch (val) { |
2039 | case 4: | ||
2040 | reg_config = &hdmi_regmap_32bit_config; | ||
2041 | hdmi->reg_shift = 2; | ||
2042 | break; | ||
2043 | case 1: | ||
2044 | reg_config = &hdmi_regmap_8bit_config; | ||
2045 | break; | ||
2046 | default: | ||
2047 | dev_err(dev, "reg-io-width must be 1 or 4\n"); | ||
2048 | return ERR_PTR(-EINVAL); | ||
2049 | } | ||
2050 | |||
2051 | iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
2052 | hdmi->regs = devm_ioremap_resource(dev, iores); | ||
2053 | if (IS_ERR(hdmi->regs)) { | ||
2054 | ret = PTR_ERR(hdmi->regs); | ||
2055 | goto err_res; | ||
2056 | } | ||
2057 | |||
2058 | hdmi->regm = devm_regmap_init_mmio(dev, hdmi->regs, reg_config); | ||
2059 | if (IS_ERR(hdmi->regm)) { | ||
2060 | dev_err(dev, "Failed to configure regmap\n"); | ||
2061 | ret = PTR_ERR(hdmi->regm); | ||
2062 | goto err_res; | ||
2063 | } | ||
2064 | } else { | ||
2065 | hdmi->regm = plat_data->regm; | ||
2059 | } | 2066 | } |
2060 | 2067 | ||
2061 | hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr"); | 2068 | hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr"); |
@@ -2165,7 +2172,7 @@ __dw_hdmi_probe(struct platform_device *pdev, | |||
2165 | config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID); | 2172 | config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID); |
2166 | config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID); | 2173 | config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID); |
2167 | 2174 | ||
2168 | if (config3 & HDMI_CONFIG3_AHBAUDDMA) { | 2175 | if (iores && config3 & HDMI_CONFIG3_AHBAUDDMA) { |
2169 | struct dw_hdmi_audio_data audio; | 2176 | struct dw_hdmi_audio_data audio; |
2170 | 2177 | ||
2171 | audio.phys = iores->start; | 2178 | audio.phys = iores->start; |
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 545f04fae3b6..bcceee8114a4 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h | |||
@@ -59,6 +59,7 @@ struct dw_hdmi_phy_ops { | |||
59 | }; | 59 | }; |
60 | 60 | ||
61 | struct dw_hdmi_plat_data { | 61 | struct dw_hdmi_plat_data { |
62 | struct regmap *regm; | ||
62 | enum drm_mode_status (*mode_valid)(struct drm_connector *connector, | 63 | enum drm_mode_status (*mode_valid)(struct drm_connector *connector, |
63 | struct drm_display_mode *mode); | 64 | struct drm_display_mode *mode); |
64 | 65 | ||