diff options
author | Andy Yan <andy.yan@rock-chips.com> | 2014-12-05 06:28:24 (GMT) |
---|---|---|
committer | Philipp Zabel <p.zabel@pengutronix.de> | 2015-01-07 17:31:57 (GMT) |
commit | 0cd9d1428322ecf379d7c2e457fbb35105f1e4a2 (patch) | |
tree | e6aee571975d17f16b0bfe9001124a0cbcdd20e1 | |
parent | cd152393967e250927bdc8013b235e66f9df5c68 (diff) | |
download | linux-0cd9d1428322ecf379d7c2e457fbb35105f1e4a2.tar.xz |
drm: bridge/dw_hdmi: add support for multi-byte register width access
On rockchip rk3288, only word(32-bit) accesses are
permitted for hdmi registers. Byte width accesses (writeb,
readb) generate an imprecise external abort.
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
Tested-by: Russell King <rmk+kernel@arm.linux.org.uk>
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
-rw-r--r-- | drivers/gpu/drm/bridge/dw_hdmi.c | 44 |
1 files changed, 42 insertions, 2 deletions
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c index ee2cbee..61f8c1f 100644 --- a/drivers/gpu/drm/bridge/dw_hdmi.c +++ b/drivers/gpu/drm/bridge/dw_hdmi.c @@ -128,18 +128,41 @@ struct dw_hdmi { unsigned int sample_rate; int ratio; + + void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); + u8 (*read)(struct dw_hdmi *hdmi, int offset); }; -static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset) +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 inline u8 hdmi_readb(struct dw_hdmi *hdmi, int 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); +} + +static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset) +{ + return hdmi->read(hdmi, offset); +} + static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg) { u8 val = hdmi_readb(hdmi, reg) & ~mask; @@ -1511,6 +1534,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master, struct device_node *ddc_node; struct dw_hdmi *hdmi; int ret; + u32 val = 1; hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); if (!hdmi) @@ -1523,6 +1547,22 @@ int dw_hdmi_bind(struct device *dev, struct device *master, hdmi->ratio = 100; hdmi->encoder = encoder; + 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 -EINVAL; + } + ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); if (ddc_node) { hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); |