From 0cd9d1428322ecf379d7c2e457fbb35105f1e4a2 Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Fri, 5 Dec 2014 14:28:24 +0800 Subject: [PATCH] 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 Tested-by: Russell King Acked-by: Russell King Signed-off-by: Philipp Zabel --- drivers/gpu/drm/bridge/dw_hdmi.c | 44 ++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c index ee2cbee8bf69..61f8c1f1cd18 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); -- 2.30.2