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@xxxxxxxxxxxxxx> --- drivers/gpu/drm/bridge/dw_hdmi.c | 57 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c index e9e73a7..52158ee 100644 --- a/drivers/gpu/drm/bridge/dw_hdmi.c +++ b/drivers/gpu/drm/bridge/dw_hdmi.c @@ -126,16 +126,39 @@ 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) @@ -1499,6 +1522,36 @@ 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 = 1; + + hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; + + hdmi->plat_data = plat_data; + hdmi->dev = &pdev->dev; + hdmi->dev_type = plat_data->dev_type; + hdmi->sample_rate = 48000; + 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; + hdmi->reg_shift = 2; + break; + case 1: + hdmi->write = dw_hdmi_writeb; + hdmi->read = dw_hdmi_readb; + hdmi->reg_shift = 0; + 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) { -- 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