uboot/drivers/clk/imx/clk-imx8qxp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright 2018 NXP
   4 * Peng Fan <peng.fan@nxp.com>
   5 */
   6
   7#include <common.h>
   8#include <clk-uclass.h>
   9#include <dm.h>
  10#include <asm/arch/sci/sci.h>
  11#include <asm/arch/clock.h>
  12#include <dt-bindings/clock/imx8qxp-clock.h>
  13#include <dt-bindings/soc/imx_rsrc.h>
  14#include <misc.h>
  15
  16#include "clk-imx8.h"
  17
  18#if CONFIG_IS_ENABLED(CMD_CLK)
  19struct imx8_clks imx8_clk_names[] = {
  20        { IMX8QXP_A35_DIV, "A35_DIV" },
  21        { IMX8QXP_I2C0_CLK, "I2C0" },
  22        { IMX8QXP_I2C1_CLK, "I2C1" },
  23        { IMX8QXP_I2C2_CLK, "I2C2" },
  24        { IMX8QXP_I2C3_CLK, "I2C3" },
  25        { IMX8QXP_UART0_CLK, "UART0" },
  26        { IMX8QXP_UART1_CLK, "UART1" },
  27        { IMX8QXP_UART2_CLK, "UART2" },
  28        { IMX8QXP_UART3_CLK, "UART3" },
  29        { IMX8QXP_SDHC0_CLK, "SDHC0" },
  30        { IMX8QXP_SDHC1_CLK, "SDHC1" },
  31        { IMX8QXP_ENET0_AHB_CLK, "ENET0_AHB" },
  32        { IMX8QXP_ENET0_IPG_CLK, "ENET0_IPG" },
  33        { IMX8QXP_ENET0_REF_DIV, "ENET0_REF" },
  34        { IMX8QXP_ENET0_PTP_CLK, "ENET0_PTP" },
  35        { IMX8QXP_ENET1_AHB_CLK, "ENET1_AHB" },
  36        { IMX8QXP_ENET1_IPG_CLK, "ENET1_IPG" },
  37        { IMX8QXP_ENET1_REF_DIV, "ENET1_REF" },
  38        { IMX8QXP_ENET1_PTP_CLK, "ENET1_PTP" },
  39};
  40
  41int num_clks = ARRAY_SIZE(imx8_clk_names);
  42#endif
  43
  44ulong imx8_clk_get_rate(struct clk *clk)
  45{
  46        sc_pm_clk_t pm_clk;
  47        ulong rate;
  48        u16 resource;
  49        int ret;
  50
  51        debug("%s(#%lu)\n", __func__, clk->id);
  52
  53        switch (clk->id) {
  54        case IMX8QXP_A35_DIV:
  55                resource = SC_R_A35;
  56                pm_clk = SC_PM_CLK_CPU;
  57                break;
  58        case IMX8QXP_I2C0_CLK:
  59                resource = SC_R_I2C_0;
  60                pm_clk = SC_PM_CLK_PER;
  61                break;
  62        case IMX8QXP_I2C1_CLK:
  63                resource = SC_R_I2C_1;
  64                pm_clk = SC_PM_CLK_PER;
  65                break;
  66        case IMX8QXP_I2C2_CLK:
  67                resource = SC_R_I2C_2;
  68                pm_clk = SC_PM_CLK_PER;
  69                break;
  70        case IMX8QXP_I2C3_CLK:
  71                resource = SC_R_I2C_3;
  72                pm_clk = SC_PM_CLK_PER;
  73                break;
  74        case IMX8QXP_SDHC0_IPG_CLK:
  75        case IMX8QXP_SDHC0_CLK:
  76        case IMX8QXP_SDHC0_DIV:
  77                resource = SC_R_SDHC_0;
  78                pm_clk = SC_PM_CLK_PER;
  79                break;
  80        case IMX8QXP_SDHC1_IPG_CLK:
  81        case IMX8QXP_SDHC1_CLK:
  82        case IMX8QXP_SDHC1_DIV:
  83                resource = SC_R_SDHC_1;
  84                pm_clk = SC_PM_CLK_PER;
  85                break;
  86        case IMX8QXP_UART0_IPG_CLK:
  87        case IMX8QXP_UART0_CLK:
  88                resource = SC_R_UART_0;
  89                pm_clk = SC_PM_CLK_PER;
  90                break;
  91        case IMX8QXP_UART1_CLK:
  92                resource = SC_R_UART_1;
  93                pm_clk = SC_PM_CLK_PER;
  94                break;
  95        case IMX8QXP_UART2_CLK:
  96                resource = SC_R_UART_2;
  97                pm_clk = SC_PM_CLK_PER;
  98                break;
  99        case IMX8QXP_UART3_CLK:
 100                resource = SC_R_UART_3;
 101                pm_clk = SC_PM_CLK_PER;
 102                break;
 103        case IMX8QXP_ENET0_IPG_CLK:
 104        case IMX8QXP_ENET0_AHB_CLK:
 105        case IMX8QXP_ENET0_REF_DIV:
 106        case IMX8QXP_ENET0_PTP_CLK:
 107                resource = SC_R_ENET_0;
 108                pm_clk = SC_PM_CLK_PER;
 109                break;
 110        case IMX8QXP_ENET1_IPG_CLK:
 111        case IMX8QXP_ENET1_AHB_CLK:
 112        case IMX8QXP_ENET1_REF_DIV:
 113        case IMX8QXP_ENET1_PTP_CLK:
 114                resource = SC_R_ENET_1;
 115                pm_clk = SC_PM_CLK_PER;
 116                break;
 117        default:
 118                if (clk->id < IMX8QXP_UART0_IPG_CLK ||
 119                    clk->id >= IMX8QXP_CLK_END) {
 120                        printf("%s(Invalid clk ID #%lu)\n",
 121                               __func__, clk->id);
 122                        return -EINVAL;
 123                }
 124                return -ENOTSUPP;
 125        };
 126
 127        ret = sc_pm_get_clock_rate(-1, resource, pm_clk,
 128                                   (sc_pm_clock_rate_t *)&rate);
 129        if (ret) {
 130                printf("%s err %d\n", __func__, ret);
 131                return ret;
 132        }
 133
 134        return rate;
 135}
 136
 137ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
 138{
 139        sc_pm_clk_t pm_clk;
 140        u32 new_rate = rate;
 141        u16 resource;
 142        int ret;
 143
 144        debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
 145
 146        switch (clk->id) {
 147        case IMX8QXP_I2C0_CLK:
 148                resource = SC_R_I2C_0;
 149                pm_clk = SC_PM_CLK_PER;
 150                break;
 151        case IMX8QXP_I2C1_CLK:
 152                resource = SC_R_I2C_1;
 153                pm_clk = SC_PM_CLK_PER;
 154                break;
 155        case IMX8QXP_I2C2_CLK:
 156                resource = SC_R_I2C_2;
 157                pm_clk = SC_PM_CLK_PER;
 158                break;
 159        case IMX8QXP_I2C3_CLK:
 160                resource = SC_R_I2C_3;
 161                pm_clk = SC_PM_CLK_PER;
 162                break;
 163        case IMX8QXP_UART0_CLK:
 164                resource = SC_R_UART_0;
 165                pm_clk = SC_PM_CLK_PER;
 166                break;
 167        case IMX8QXP_UART1_CLK:
 168                resource = SC_R_UART_1;
 169                pm_clk = SC_PM_CLK_PER;
 170                break;
 171        case IMX8QXP_UART2_CLK:
 172                resource = SC_R_UART_2;
 173                pm_clk = SC_PM_CLK_PER;
 174                break;
 175        case IMX8QXP_UART3_CLK:
 176                resource = SC_R_UART_3;
 177                pm_clk = SC_PM_CLK_PER;
 178                break;
 179        case IMX8QXP_SDHC0_IPG_CLK:
 180        case IMX8QXP_SDHC0_CLK:
 181        case IMX8QXP_SDHC0_DIV:
 182                resource = SC_R_SDHC_0;
 183                pm_clk = SC_PM_CLK_PER;
 184                break;
 185        case IMX8QXP_SDHC1_SEL:
 186        case IMX8QXP_SDHC0_SEL:
 187                return 0;
 188        case IMX8QXP_SDHC1_IPG_CLK:
 189        case IMX8QXP_SDHC1_CLK:
 190        case IMX8QXP_SDHC1_DIV:
 191                resource = SC_R_SDHC_1;
 192                pm_clk = SC_PM_CLK_PER;
 193                break;
 194        case IMX8QXP_ENET0_IPG_CLK:
 195        case IMX8QXP_ENET0_AHB_CLK:
 196        case IMX8QXP_ENET0_REF_DIV:
 197        case IMX8QXP_ENET0_PTP_CLK:
 198                resource = SC_R_ENET_0;
 199                pm_clk = SC_PM_CLK_PER;
 200                break;
 201        case IMX8QXP_ENET1_IPG_CLK:
 202        case IMX8QXP_ENET1_AHB_CLK:
 203        case IMX8QXP_ENET1_REF_DIV:
 204        case IMX8QXP_ENET1_PTP_CLK:
 205                resource = SC_R_ENET_1;
 206                pm_clk = SC_PM_CLK_PER;
 207                break;
 208        default:
 209                if (clk->id < IMX8QXP_UART0_IPG_CLK ||
 210                    clk->id >= IMX8QXP_CLK_END) {
 211                        printf("%s(Invalid clk ID #%lu)\n",
 212                               __func__, clk->id);
 213                        return -EINVAL;
 214                }
 215                return -ENOTSUPP;
 216        };
 217
 218        ret = sc_pm_set_clock_rate(-1, resource, pm_clk, &new_rate);
 219        if (ret) {
 220                printf("%s err %d\n", __func__, ret);
 221                return ret;
 222        }
 223
 224        return new_rate;
 225}
 226
 227int __imx8_clk_enable(struct clk *clk, bool enable)
 228{
 229        sc_pm_clk_t pm_clk;
 230        u16 resource;
 231        int ret;
 232
 233        debug("%s(#%lu)\n", __func__, clk->id);
 234
 235        switch (clk->id) {
 236        case IMX8QXP_I2C0_CLK:
 237                resource = SC_R_I2C_0;
 238                pm_clk = SC_PM_CLK_PER;
 239                break;
 240        case IMX8QXP_I2C1_CLK:
 241                resource = SC_R_I2C_1;
 242                pm_clk = SC_PM_CLK_PER;
 243                break;
 244        case IMX8QXP_I2C2_CLK:
 245                resource = SC_R_I2C_2;
 246                pm_clk = SC_PM_CLK_PER;
 247                break;
 248        case IMX8QXP_I2C3_CLK:
 249                resource = SC_R_I2C_3;
 250                pm_clk = SC_PM_CLK_PER;
 251                break;
 252        case IMX8QXP_UART0_CLK:
 253                resource = SC_R_UART_0;
 254                pm_clk = SC_PM_CLK_PER;
 255                break;
 256        case IMX8QXP_UART1_CLK:
 257                resource = SC_R_UART_1;
 258                pm_clk = SC_PM_CLK_PER;
 259                break;
 260        case IMX8QXP_UART2_CLK:
 261                resource = SC_R_UART_2;
 262                pm_clk = SC_PM_CLK_PER;
 263                break;
 264        case IMX8QXP_UART3_CLK:
 265                resource = SC_R_UART_3;
 266                pm_clk = SC_PM_CLK_PER;
 267                break;
 268        case IMX8QXP_SDHC0_IPG_CLK:
 269        case IMX8QXP_SDHC0_CLK:
 270        case IMX8QXP_SDHC0_DIV:
 271                resource = SC_R_SDHC_0;
 272                pm_clk = SC_PM_CLK_PER;
 273                break;
 274        case IMX8QXP_SDHC1_IPG_CLK:
 275        case IMX8QXP_SDHC1_CLK:
 276        case IMX8QXP_SDHC1_DIV:
 277                resource = SC_R_SDHC_1;
 278                pm_clk = SC_PM_CLK_PER;
 279                break;
 280        case IMX8QXP_ENET0_IPG_CLK:
 281        case IMX8QXP_ENET0_AHB_CLK:
 282        case IMX8QXP_ENET0_REF_DIV:
 283        case IMX8QXP_ENET0_PTP_CLK:
 284                resource = SC_R_ENET_0;
 285                pm_clk = SC_PM_CLK_PER;
 286                break;
 287        case IMX8QXP_ENET1_IPG_CLK:
 288        case IMX8QXP_ENET1_AHB_CLK:
 289        case IMX8QXP_ENET1_REF_DIV:
 290        case IMX8QXP_ENET1_PTP_CLK:
 291                resource = SC_R_ENET_1;
 292                pm_clk = SC_PM_CLK_PER;
 293                break;
 294        default:
 295                if (clk->id < IMX8QXP_UART0_IPG_CLK ||
 296                    clk->id >= IMX8QXP_CLK_END) {
 297                        printf("%s(Invalid clk ID #%lu)\n",
 298                               __func__, clk->id);
 299                        return -EINVAL;
 300                }
 301                return -ENOTSUPP;
 302        }
 303
 304        ret = sc_pm_clock_enable(-1, resource, pm_clk, enable, 0);
 305        if (ret) {
 306                printf("%s err %d\n", __func__, ret);
 307                return ret;
 308        }
 309
 310        return 0;
 311}
 312