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