video: xilinxfb: Add support for little endian accesses
[cascardo/linux.git] / drivers / video / xilinxfb.c
index 1b55f18..f3d4a69 100644 (file)
@@ -117,6 +117,7 @@ static struct fb_var_screeninfo xilinx_fb_var = {
 
 
 #define BUS_ACCESS_FLAG                0x1 /* 1 = BUS, 0 = DCR */
+#define LITTLE_ENDIAN_ACCESS   0x2 /* LITTLE ENDIAN IO functions */
 
 struct xilinxfb_drvdata {
 
@@ -153,14 +154,33 @@ struct xilinxfb_drvdata {
 static void xilinx_fb_out32(struct xilinxfb_drvdata *drvdata, u32 offset,
                                u32 val)
 {
-       if (drvdata->flags & BUS_ACCESS_FLAG)
-               out_be32(drvdata->regs + (offset << 2), val);
+       if (drvdata->flags & BUS_ACCESS_FLAG) {
+               if (drvdata->flags & LITTLE_ENDIAN_ACCESS)
+                       iowrite32(val, drvdata->regs + (offset << 2));
+               else
+                       iowrite32be(val, drvdata->regs + (offset << 2));
+       }
 #ifdef CONFIG_PPC_DCR
        else
                dcr_write(drvdata->dcr_host, offset, val);
 #endif
 }
 
+static u32 xilinx_fb_in32(struct xilinxfb_drvdata *drvdata, u32 offset)
+{
+       if (drvdata->flags & BUS_ACCESS_FLAG) {
+               if (drvdata->flags & LITTLE_ENDIAN_ACCESS)
+                       return ioread32(drvdata->regs + (offset << 2));
+               else
+                       return ioread32be(drvdata->regs + (offset << 2));
+       }
+#ifdef CONFIG_PPC_DCR
+       else
+               return dcr_read(drvdata->dcr_host, offset);
+#endif
+       return 0;
+}
+
 static int
 xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
        unsigned transp, struct fb_info *fbi)
@@ -227,33 +247,23 @@ static struct fb_ops xilinxfb_ops =
  * Bus independent setup/teardown
  */
 
-static int xilinxfb_assign(struct device *dev,
+static int xilinxfb_assign(struct platform_device *pdev,
                           struct xilinxfb_drvdata *drvdata,
-                          unsigned long physaddr,
                           struct xilinxfb_platform_data *pdata)
 {
        int rc;
+       struct device *dev = &pdev->dev;
        int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL;
 
        if (drvdata->flags & BUS_ACCESS_FLAG) {
-               /*
-                * Map the control registers in if the controller
-                * is on direct BUS interface.
-                */
-               if (!request_mem_region(physaddr, 8, DRIVER_NAME)) {
-                       dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
-                               physaddr);
-                       rc = -ENODEV;
-                       goto err_region;
-               }
+               struct resource *res;
 
-               drvdata->regs_phys = physaddr;
-               drvdata->regs = ioremap(physaddr, 8);
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               drvdata->regs_phys = res->start;
+               drvdata->regs = devm_request_and_ioremap(&pdev->dev, res);
                if (!drvdata->regs) {
-                       dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
-                               physaddr);
-                       rc = -ENODEV;
-                       goto err_map;
+                       rc = -EADDRNOTAVAIL;
+                       goto err_region;
                }
        }
 
@@ -281,6 +291,12 @@ static int xilinxfb_assign(struct device *dev,
 
        /* Tell the hardware where the frame buffer is */
        xilinx_fb_out32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
+       rc = xilinx_fb_in32(drvdata, REG_FB_ADDR);
+       /* Endianess detection */
+       if (rc != drvdata->fb_phys) {
+               drvdata->flags |= LITTLE_ENDIAN_ACCESS;
+               xilinx_fb_out32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
+       }
 
        /* Turn on the display */
        drvdata->reg_ctrl_default = REG_CTRL_ENABLE;
@@ -349,11 +365,7 @@ err_cmap:
 
 err_fbmem:
        if (drvdata->flags & BUS_ACCESS_FLAG)
-               iounmap(drvdata->regs);
-
-err_map:
-       if (drvdata->flags & BUS_ACCESS_FLAG)
-               release_mem_region(drvdata->regs_phys, 8);
+               devm_iounmap(dev, drvdata->regs);
 
 err_region:
        kfree(drvdata);
@@ -384,10 +396,8 @@ static int xilinxfb_release(struct device *dev)
        xilinx_fb_out32(drvdata, REG_CTRL, 0);
 
        /* Release the resources, as allocated based on interface */
-       if (drvdata->flags & BUS_ACCESS_FLAG) {
-               iounmap(drvdata->regs);
-               release_mem_region(drvdata->regs_phys, 8);
-       }
+       if (drvdata->flags & BUS_ACCESS_FLAG)
+               devm_iounmap(dev, drvdata->regs);
 #ifdef CONFIG_PPC_DCR
        else
                dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
@@ -408,8 +418,7 @@ static int xilinxfb_of_probe(struct platform_device *op)
        const u32 *prop;
        u32 tft_access = 0;
        struct xilinxfb_platform_data pdata;
-       struct resource res;
-       int size, rc;
+       int size;
        struct xilinxfb_drvdata *drvdata;
 
        /* Copy with the default pdata (not a ptr reference!) */
@@ -435,22 +444,17 @@ static int xilinxfb_of_probe(struct platform_device *op)
         */
        if (tft_access) {
                drvdata->flags |= BUS_ACCESS_FLAG;
-               rc = of_address_to_resource(op->dev.of_node, 0, &res);
-               if (rc) {
-                       dev_err(&op->dev, "invalid address\n");
-                       goto err;
-               }
        }
 #ifdef CONFIG_PPC_DCR
        else {
                int start;
-               res.start = 0;
                start = dcr_resource_start(op->dev.of_node, 0);
                drvdata->dcr_len = dcr_resource_len(op->dev.of_node, 0);
                drvdata->dcr_host = dcr_map(op->dev.of_node, start, drvdata->dcr_len);
                if (!DCR_MAP_OK(drvdata->dcr_host)) {
                        dev_err(&op->dev, "invalid DCR address\n");
-                       goto err;
+                       kfree(drvdata);
+                       return -ENODEV;
                }
        }
 #endif
@@ -477,11 +481,7 @@ static int xilinxfb_of_probe(struct platform_device *op)
                pdata.rotate_screen = 1;
 
        dev_set_drvdata(&op->dev, drvdata);
-       return xilinxfb_assign(&op->dev, drvdata, res.start, &pdata);
-
- err:
-       kfree(drvdata);
-       return -ENODEV;
+       return xilinxfb_assign(op, drvdata, &pdata);
 }
 
 static int xilinxfb_of_remove(struct platform_device *op)