powerpc/85xx: p1022ds: enable monitor switching via pixis indirect mode
authorTimur Tabi <timur@freescale.com>
Fri, 18 Nov 2011 07:50:01 +0000 (07:50 +0000)
committerKumar Gala <galak@kernel.crashing.org>
Fri, 16 Mar 2012 16:16:16 +0000 (11:16 -0500)
When the P1022's DIU video controller is active, the pixis must be accessed
in "indirect" mode, which uses localbus chip select addresses.

Switching between the DVI and LVDS monitor ports is handled by the pixis,
so that switching needs to be done via indirect mode.

This has the side-effect of no longer requiring U-Boot to enable the DIU.
Now Linux can enable the DIU all by itself.

Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
arch/powerpc/platforms/85xx/p1022_ds.c

index e211b0d756f03e361b88f1e841f92810522deb15..0fe88e39945ecd5e4b13dee9ec03e362e0ebdfe8 100644 (file)
 
 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
 
+#define PMUXCR_ELBCDIU_MASK    0xc0000000
+#define PMUXCR_ELBCDIU_NOR16   0x80000000
+#define PMUXCR_ELBCDIU_DIU     0x40000000
+
 /*
  * Board-specific initialization of the DIU.  This code should probably be
  * executed when the DIU is opened, rather than in arch code, but the DIU
 #define CLKDVDR_PXCLK_MASK     0x00FF0000
 
 /* Some ngPIXIS register definitions */
+#define PX_CTL         3
+#define PX_BRDCFG0     8
+#define PX_BRDCFG1     9
+
+#define PX_BRDCFG0_ELBC_SPI_MASK       0xc0
+#define PX_BRDCFG0_ELBC_SPI_ELBC       0x00
+#define PX_BRDCFG0_ELBC_SPI_NULL       0xc0
+#define PX_BRDCFG0_ELBC_DIU            0x02
+
 #define PX_BRDCFG1_DVIEN       0x80
 #define PX_BRDCFG1_DFPEN       0x40
 #define PX_BRDCFG1_BACKLIGHT   0x20
 #define PX_BRDCFG1_DDCEN       0x10
 
+#define PX_CTL_ALTACC          0x80
+
 /*
  * DIU Area Descriptor
  *
@@ -133,44 +148,117 @@ static void p1022ds_set_gamma_table(enum fsl_diu_monitor_port port,
  */
 static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port)
 {
-       struct device_node *np;
-       void __iomem *pixis;
-       u8 __iomem *brdcfg1;
-
-       np = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga");
-       if (!np)
-               /* older device trees used "fsl,p1022ds-pixis" */
-               np = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-pixis");
-       if (!np) {
-               pr_err("p1022ds: missing ngPIXIS node\n");
+       struct device_node *guts_node;
+       struct device_node *indirect_node = NULL;
+       struct ccsr_guts_85xx __iomem *guts;
+       u8 __iomem *lbc_lcs0_ba = NULL;
+       u8 __iomem *lbc_lcs1_ba = NULL;
+       u8 b;
+
+       /* Map the global utilities registers. */
+       guts_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
+       if (!guts_node) {
+               pr_err("p1022ds: missing global utilties device node\n");
                return;
        }
 
-       pixis = of_iomap(np, 0);
-       if (!pixis) {
-               pr_err("p1022ds: could not map ngPIXIS registers\n");
-               return;
+       guts = of_iomap(guts_node, 0);
+       if (!guts) {
+               pr_err("p1022ds: could not map global utilties device\n");
+               goto exit;
+       }
+
+       indirect_node = of_find_compatible_node(NULL, NULL,
+                                            "fsl,p1022ds-indirect-pixis");
+       if (!indirect_node) {
+               pr_err("p1022ds: missing pixis indirect mode node\n");
+               goto exit;
        }
-       brdcfg1 = pixis + 9;    /* BRDCFG1 is at offset 9 in the ngPIXIS */
+
+       lbc_lcs0_ba = of_iomap(indirect_node, 0);
+       if (!lbc_lcs0_ba) {
+               pr_err("p1022ds: could not map localbus chip select 0\n");
+               goto exit;
+       }
+
+       lbc_lcs1_ba = of_iomap(indirect_node, 1);
+       if (!lbc_lcs1_ba) {
+               pr_err("p1022ds: could not map localbus chip select 1\n");
+               goto exit;
+       }
+
+       /* Make sure we're in indirect mode first. */
+       if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) !=
+           PMUXCR_ELBCDIU_DIU) {
+               struct device_node *pixis_node;
+               void __iomem *pixis;
+
+               pixis_node =
+                       of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga");
+               if (!pixis_node) {
+                       pr_err("p1022ds: missing pixis node\n");
+                       goto exit;
+               }
+
+               pixis = of_iomap(pixis_node, 0);
+               of_node_put(pixis_node);
+               if (!pixis) {
+                       pr_err("p1022ds: could not map pixis registers\n");
+                       goto exit;
+               }
+
+               /* Enable indirect PIXIS mode.  */
+               setbits8(pixis + PX_CTL, PX_CTL_ALTACC);
+               iounmap(pixis);
+
+               /* Switch the board mux to the DIU */
+               out_8(lbc_lcs0_ba, PX_BRDCFG0); /* BRDCFG0 */
+               b = in_8(lbc_lcs1_ba);
+               b |= PX_BRDCFG0_ELBC_DIU;
+               out_8(lbc_lcs1_ba, b);
+
+               /* Set the chip mux to DIU mode. */
+               clrsetbits_be32(&guts->pmuxcr, PMUXCR_ELBCDIU_MASK,
+                               PMUXCR_ELBCDIU_DIU);
+               in_be32(&guts->pmuxcr);
+       }
+
 
        switch (port) {
        case FSL_DIU_PORT_DVI:
-               printk(KERN_INFO "%s:%u\n", __func__, __LINE__);
                /* Enable the DVI port, disable the DFP and the backlight */
-               clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT,
-                            PX_BRDCFG1_DVIEN);
+               out_8(lbc_lcs0_ba, PX_BRDCFG1);
+               b = in_8(lbc_lcs1_ba);
+               b &= ~(PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT);
+               b |= PX_BRDCFG1_DVIEN;
+               out_8(lbc_lcs1_ba, b);
                break;
        case FSL_DIU_PORT_LVDS:
-               printk(KERN_INFO "%s:%u\n", __func__, __LINE__);
+               /*
+                * LVDS also needs backlight enabled, otherwise the display
+                * will be blank.
+                */
                /* Enable the DFP port, disable the DVI and the backlight */
-               clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT,
-                            PX_BRDCFG1_DFPEN);
+               out_8(lbc_lcs0_ba, PX_BRDCFG1);
+               b = in_8(lbc_lcs1_ba);
+               b &= ~PX_BRDCFG1_DVIEN;
+               b |= PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT;
+               out_8(lbc_lcs1_ba, b);
                break;
        default:
                pr_err("p1022ds: unsupported monitor port %i\n", port);
        }
 
-       iounmap(pixis);
+exit:
+       if (lbc_lcs1_ba)
+               iounmap(lbc_lcs1_ba);
+       if (lbc_lcs0_ba)
+               iounmap(lbc_lcs0_ba);
+       if (guts)
+               iounmap(guts);
+
+       of_node_put(indirect_node);
+       of_node_put(guts_node);
 }
 
 /**