uboot/arch/arm/mach-omap2/pipe3-phy.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * TI PIPE3 PHY
   4 *
   5 * (C) Copyright 2013
   6 * Texas Instruments, <www.ti.com>
   7 */
   8
   9#include <common.h>
  10#include <sata.h>
  11#include <asm/arch/clock.h>
  12#include <asm/arch/sys_proto.h>
  13#include <asm/io.h>
  14#include <linux/bitops.h>
  15#include <linux/delay.h>
  16#include <linux/errno.h>
  17#include "pipe3-phy.h"
  18
  19/* PLLCTRL Registers */
  20#define PLL_STATUS              0x00000004
  21#define PLL_GO                  0x00000008
  22#define PLL_CONFIGURATION1      0x0000000C
  23#define PLL_CONFIGURATION2      0x00000010
  24#define PLL_CONFIGURATION3      0x00000014
  25#define PLL_CONFIGURATION4      0x00000020
  26
  27#define PLL_REGM_MASK           0x001FFE00
  28#define PLL_REGM_SHIFT          9
  29#define PLL_REGM_F_MASK         0x0003FFFF
  30#define PLL_REGM_F_SHIFT        0
  31#define PLL_REGN_MASK           0x000001FE
  32#define PLL_REGN_SHIFT          1
  33#define PLL_SELFREQDCO_MASK     0x0000000E
  34#define PLL_SELFREQDCO_SHIFT    1
  35#define PLL_SD_MASK             0x0003FC00
  36#define PLL_SD_SHIFT            10
  37#define SET_PLL_GO              0x1
  38#define PLL_TICOPWDN            BIT(16)
  39#define PLL_LDOPWDN             BIT(15)
  40#define PLL_LOCK                0x2
  41#define PLL_IDLE                0x1
  42
  43/* PHY POWER CONTROL Register */
  44#define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK         0x003FC000
  45#define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT        0xE
  46
  47#define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK        0xFFC00000
  48#define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT       0x16
  49
  50#define OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON       0x3
  51#define OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF      0x0
  52
  53
  54#define PLL_IDLE_TIME   100     /* in milliseconds */
  55#define PLL_LOCK_TIME   100     /* in milliseconds */
  56
  57static inline u32 omap_pipe3_readl(void __iomem *addr, unsigned offset)
  58{
  59        return __raw_readl(addr + offset);
  60}
  61
  62static inline void omap_pipe3_writel(void __iomem *addr, unsigned offset,
  63                u32 data)
  64{
  65        __raw_writel(data, addr + offset);
  66}
  67
  68static struct pipe3_dpll_params *omap_pipe3_get_dpll_params(struct omap_pipe3
  69                                                                        *pipe3)
  70{
  71        u32 rate;
  72        struct pipe3_dpll_map *dpll_map = pipe3->dpll_map;
  73
  74        rate = get_sys_clk_freq();
  75
  76        for (; dpll_map->rate; dpll_map++) {
  77                if (rate == dpll_map->rate)
  78                        return &dpll_map->params;
  79        }
  80
  81        printf("%s: No DPLL configuration for %u Hz SYS CLK\n",
  82               __func__, rate);
  83        return NULL;
  84}
  85
  86
  87static int omap_pipe3_wait_lock(struct omap_pipe3 *phy)
  88{
  89        u32 val;
  90        int timeout = PLL_LOCK_TIME;
  91
  92        do {
  93                mdelay(1);
  94                val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
  95                if (val & PLL_LOCK)
  96                        break;
  97        } while (--timeout);
  98
  99        if (!(val & PLL_LOCK)) {
 100                printf("%s: DPLL failed to lock\n", __func__);
 101                return -EBUSY;
 102        }
 103
 104        return 0;
 105}
 106
 107static int omap_pipe3_dpll_program(struct omap_pipe3 *phy)
 108{
 109        u32                     val;
 110        struct pipe3_dpll_params *dpll_params;
 111
 112        dpll_params = omap_pipe3_get_dpll_params(phy);
 113        if (!dpll_params) {
 114                printf("%s: Invalid DPLL parameters\n", __func__);
 115                return -EINVAL;
 116        }
 117
 118        val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
 119        val &= ~PLL_REGN_MASK;
 120        val |= dpll_params->n << PLL_REGN_SHIFT;
 121        omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
 122
 123        val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
 124        val &= ~PLL_SELFREQDCO_MASK;
 125        val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
 126        omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
 127
 128        val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
 129        val &= ~PLL_REGM_MASK;
 130        val |= dpll_params->m << PLL_REGM_SHIFT;
 131        omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
 132
 133        val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4);
 134        val &= ~PLL_REGM_F_MASK;
 135        val |= dpll_params->mf << PLL_REGM_F_SHIFT;
 136        omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val);
 137
 138        val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3);
 139        val &= ~PLL_SD_MASK;
 140        val |= dpll_params->sd << PLL_SD_SHIFT;
 141        omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val);
 142
 143        omap_pipe3_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO);
 144
 145        return omap_pipe3_wait_lock(phy);
 146}
 147
 148static void omap_control_phy_power(struct omap_pipe3 *phy, int on)
 149{
 150        u32 val, rate;
 151
 152        val = readl(phy->power_reg);
 153
 154        rate = get_sys_clk_freq();
 155        rate = rate/1000000;
 156
 157        if (on) {
 158                val &= ~(OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK |
 159                                OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK);
 160                val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON <<
 161                        OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
 162                val |= rate <<
 163                        OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT;
 164        } else {
 165                val &= ~OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK;
 166                val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF <<
 167                        OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
 168        }
 169
 170        writel(val, phy->power_reg);
 171}
 172
 173int phy_pipe3_power_on(struct omap_pipe3 *phy)
 174{
 175        int ret;
 176        u32 val;
 177
 178        /* Program the DPLL only if not locked */
 179        val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
 180        if (!(val & PLL_LOCK)) {
 181                ret = omap_pipe3_dpll_program(phy);
 182                if (ret)
 183                        return ret;
 184        } else {
 185                /* else just bring it out of IDLE mode */
 186                val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
 187                if (val & PLL_IDLE) {
 188                        val &= ~PLL_IDLE;
 189                        omap_pipe3_writel(phy->pll_ctrl_base,
 190                                          PLL_CONFIGURATION2, val);
 191                        ret = omap_pipe3_wait_lock(phy);
 192                        if (ret)
 193                                return ret;
 194                }
 195        }
 196
 197        /* Power up the PHY */
 198        omap_control_phy_power(phy, 1);
 199
 200        return 0;
 201}
 202
 203int phy_pipe3_power_off(struct omap_pipe3 *phy)
 204{
 205        u32 val;
 206        int timeout = PLL_IDLE_TIME;
 207
 208        /* Power down the PHY */
 209        omap_control_phy_power(phy, 0);
 210
 211        /* Put DPLL in IDLE mode */
 212        val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
 213        val |= PLL_IDLE;
 214        omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
 215
 216        /* wait for LDO and Oscillator to power down */
 217        do {
 218                mdelay(1);
 219                val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
 220                if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
 221                        break;
 222        } while (--timeout);
 223
 224        if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
 225                printf("%s: Failed to power down DPLL: PLL_STATUS 0x%x\n",
 226                       __func__, val);
 227                return -EBUSY;
 228        }
 229
 230        return 0;
 231}
 232