On rockchip rk3288, only word(32-bit) accesses are permitted for hdmi registers. Byte width access (writeb, readb) generate an imprecise external abort. Signed-off-by: Andy Yan <andy.yan@xxxxxxxxxxxxxx> --- drivers/gpu/drm/bridge/dw_hdmi.c | 53 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c index e561286..a34f928 100644 --- a/drivers/gpu/drm/bridge/dw_hdmi.c +++ b/drivers/gpu/drm/bridge/dw_hdmi.c @@ -126,19 +126,42 @@ struct dw_hdmi { unsigned int sample_rate; int ratio; + void (*write)(u8 val, void __iomem *addr); + u8 (*read)(void __iomem *addr); + int reg_shift; }; +static void dw_hdmi_writel(u8 val, void __iomem *addr) +{ + writel(val, addr); +} + +static u8 dw_hdmi_readl(void __iomem *addr) +{ + return readl(addr); +} + +static void dw_hdmi_writeb(u8 val, void __iomem *addr) +{ + writeb(val, addr); +} + +static u8 dw_hdmi_readb(void __iomem *addr) +{ + return readb(addr); +} + static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset) { - writeb(val, hdmi->regs + offset); + hdmi->write(val, hdmi->regs + (offset << hdmi->reg_shift)); } static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset) { - return readb(hdmi->regs + offset); + return hdmi->read(hdmi->regs + (offset << hdmi->reg_shift)); } -static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg) +static void hdmi_modb(struct dw_hdmi *hdmi, u32 data, u32 mask, unsigned reg) { u8 val = hdmi_readb(hdmi, reg) & ~mask; @@ -146,8 +169,8 @@ static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg) hdmi_writeb(hdmi, val, reg); } -static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg, - u8 shift, u8 mask) +static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u32 data, unsigned int reg, + u32 shift, u32 mask) { hdmi_modb(hdmi, data << shift, mask, reg); } @@ -1500,6 +1523,26 @@ static int dw_hdmi_bind(struct device *dev, struct device *master, void *data) struct device_node *ddc_node; struct resource *iores; int ret, irq; + u32 val; + + if (!of_property_read_u32(np, "reg-io-width", &val)) { + switch (val) { + case 4: + hdmi->write = dw_hdmi_writel; + hdmi->read = dw_hdmi_readl; + hdmi->reg_shift = 2; + break; + default: + hdmi->write = dw_hdmi_writeb; + hdmi->read = dw_hdmi_readb; + hdmi->reg_shift = 0; + break; + } + } else { + hdmi->write = dw_hdmi_writeb; + hdmi->read = dw_hdmi_readb; + hdmi->reg_shift = 0; + } ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); if (ddc_node) { -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html