davinci: enable easy top down traversal of clock tree
[safe/jmp/linux-2.6] / arch / arm / mach-davinci / psc.c
index e1b0050..a78b657 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
-#include <asm/hardware.h>
-#include <asm/arch/psc.h>
+#include <mach/cputype.h>
+#include <mach/hardware.h>
+#include <mach/psc.h>
+#include <mach/mux.h>
 
-#define PTCMD       __REG(0x01C41120)
-#define PDSTAT      __REG(0x01C41200)
-#define PDCTL1      __REG(0x01C41304)
-#define EPCPR       __REG(0x01C41070)
-#define PTSTAT      __REG(0x01C41128)
+/* PSC register offsets */
+#define EPCPR          0x070
+#define PTCMD          0x120
+#define PTSTAT         0x128
+#define PDSTAT         0x200
+#define PDCTL1         0x304
+#define MDSTAT         0x800
+#define MDCTL          0xA00
 
-#define MDSTAT      IO_ADDRESS(0x01C41800)
-#define MDCTL       IO_ADDRESS(0x01C41A00)
+#define MDSTAT_STATE_MASK 0x1f
 
-#define PINMUX0             __REG(0x01c40000)
-#define PINMUX1             __REG(0x01c40004)
-#define VDD3P3V_PWDN __REG(0x01C40048)
-
-static void davinci_psc_mux(unsigned int id)
+/* Return nonzero iff the domain's clock is active */
+int __init davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id)
 {
-       switch (id) {
-       case DAVINCI_LPSC_ATA:
-               PINMUX0 |= (1 << 17) | (1 << 16);
-               break;
-       case DAVINCI_LPSC_MMC_SD:
-               /* VDD power manupulations are done in U-Boot for CPMAC
-                * so applies to MMC as well
-                */
-               /*Set up the pull regiter for MMC */
-               VDD3P3V_PWDN = 0x0;
-               PINMUX1 &= (~(1 << 9));
-               break;
-       case DAVINCI_LPSC_I2C:
-               PINMUX1 |= (1 << 7);
-               break;
-       case DAVINCI_LPSC_McBSP:
-               PINMUX1 |= (1 << 10);
-               break;
-       default:
-               break;
+       void __iomem *psc_base;
+       u32 mdstat;
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+       if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) {
+               pr_warning("PSC: Bad psc data: 0x%x[%d]\n",
+                               (int)soc_info->psc_bases, ctlr);
+               return 0;
        }
+
+       psc_base = soc_info->psc_bases[ctlr];
+       mdstat = __raw_readl(psc_base + MDSTAT + 4 * id);
+
+       /* if clocked, state can be "Enable" or "SyncReset" */
+       return mdstat & BIT(12);
 }
 
 /* Enable or disable a PSC domain */
-void davinci_psc_config(unsigned int domain, unsigned int id, char enable)
+void davinci_psc_config(unsigned int domain, unsigned int ctlr,
+               unsigned int id, char enable)
 {
-       volatile unsigned int *mdstat = (unsigned int *)((int)MDSTAT + 4 * id);
-       volatile unsigned int *mdctl = (unsigned int *)((int)MDCTL + 4 * id);
+       u32 epcpr, ptcmd, ptstat, pdstat, pdctl1, mdstat, mdctl;
+       void __iomem *psc_base;
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+       u32 next_state = enable ? 0x3 : 0x2; /* 0x3 enables, 0x2 disables */
 
-       if (id < 0)
+       if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) {
+               pr_warning("PSC: Bad psc data: 0x%x[%d]\n",
+                               (int)soc_info->psc_bases, ctlr);
                return;
+       }
 
-       if (enable)
-               *mdctl |= 0x00000003;   /* Enable Module */
-       else
-               *mdctl &= 0xFFFFFFF2;   /* Disable Module */
+       psc_base = soc_info->psc_bases[ctlr];
 
-       if ((PDSTAT & 0x00000001) == 0) {
-               PDCTL1 |= 0x1;
-               PTCMD = (1 << domain);
-               while ((((EPCPR >> domain) & 1) == 0));
+       mdctl = __raw_readl(psc_base + MDCTL + 4 * id);
+       mdctl &= ~MDSTAT_STATE_MASK;
+       mdctl |= next_state;
+       __raw_writel(mdctl, psc_base + MDCTL + 4 * id);
 
-               PDCTL1 |= 0x100;
-               while (!(((PTSTAT >> domain) & 1) == 0));
-       } else {
-               PTCMD = (1 << domain);
-               while (!(((PTSTAT >> domain) & 1) == 0));
-       }
+       pdstat = __raw_readl(psc_base + PDSTAT);
+       if ((pdstat & 0x00000001) == 0) {
+               pdctl1 = __raw_readl(psc_base + PDCTL1);
+               pdctl1 |= 0x1;
+               __raw_writel(pdctl1, psc_base + PDCTL1);
 
-       if (enable)
-               while (!((*mdstat & 0x0000001F) == 0x3));
-       else
-               while (!((*mdstat & 0x0000001F) == 0x2));
+               ptcmd = 1 << domain;
+               __raw_writel(ptcmd, psc_base + PTCMD);
 
-       if (enable)
-               davinci_psc_mux(id);
-}
+               do {
+                       epcpr = __raw_readl(psc_base + EPCPR);
+               } while ((((epcpr >> domain) & 1) == 0));
 
-void __init davinci_psc_init(void)
-{
-       davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_VPSSMSTR, 1);
-       davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_VPSSSLV, 1);
-       davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TPCC, 1);
-       davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TPTC0, 1);
-       davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TPTC1, 1);
-       davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_GPIO, 1);
-
-       /* Turn on WatchDog timer LPSC.  Needed for RESET to work */
-       davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TIMER2, 1);
+               pdctl1 = __raw_readl(psc_base + PDCTL1);
+               pdctl1 |= 0x100;
+               __raw_writel(pdctl1, psc_base + PDCTL1);
+
+               do {
+                       ptstat = __raw_readl(psc_base +
+                                              PTSTAT);
+               } while (!(((ptstat >> domain) & 1) == 0));
+       } else {
+               ptcmd = 1 << domain;
+               __raw_writel(ptcmd, psc_base + PTCMD);
+
+               do {
+                       ptstat = __raw_readl(psc_base + PTSTAT);
+               } while (!(((ptstat >> domain) & 1) == 0));
+       }
+
+       do {
+               mdstat = __raw_readl(psc_base + MDSTAT + 4 * id);
+       } while (!((mdstat & MDSTAT_STATE_MASK) == next_state));
 }