1 /* 2 * (C) Copyright 2017 Rockchip Electronics Co., Ltd 3 * Author: Andy Yan <andy.yan@rock-chips.com> 4 * (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH 5 * SPDX-License-Identifier: GPL-2.0 6 */ 7 8 #include <common.h> 9 #include <clk-uclass.h> 10 #include <dm.h> 11 #include <dt-structs.h> 12 #include <errno.h> 13 #include <mapmem.h> 14 #include <syscon.h> 15 #include <bitfield.h> 16 #include <asm/arch/clock.h> 17 #include <asm/arch/cru_rk3368.h> 18 #include <asm/arch/hardware.h> 19 #include <asm/io.h> 20 #include <dm/lists.h> 21 #include <dt-bindings/clock/rk3368-cru.h> 22 23 DECLARE_GLOBAL_DATA_PTR; 24 25 #if CONFIG_IS_ENABLED(OF_PLATDATA) 26 struct rk3368_clk_plat { 27 struct dtd_rockchip_rk3368_cru dtd; 28 }; 29 #endif 30 31 struct pll_div { 32 u32 nr; 33 u32 nf; 34 u32 no; 35 }; 36 37 #define OSC_HZ (24 * 1000 * 1000) 38 #define APLL_L_HZ (800 * 1000 * 1000) 39 #define APLL_B_HZ (816 * 1000 * 1000) 40 #define GPLL_HZ (576 * 1000 * 1000) 41 #define CPLL_HZ (400 * 1000 * 1000) 42 43 #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) 44 45 #define PLL_DIVISORS(hz, _nr, _no) { \ 46 .nr = _nr, .nf = (u32)((u64)hz * _nr * _no / OSC_HZ), .no = _no}; \ 47 _Static_assert(((u64)hz * _nr * _no / OSC_HZ) * OSC_HZ /\ 48 (_nr * _no) == hz, #hz "Hz cannot be hit with PLL " \ 49 "divisors on line " __stringify(__LINE__)); 50 51 #if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD) 52 static const struct pll_div apll_l_init_cfg = PLL_DIVISORS(APLL_L_HZ, 12, 2); 53 static const struct pll_div apll_b_init_cfg = PLL_DIVISORS(APLL_B_HZ, 1, 2); 54 #if !defined(CONFIG_TPL_BUILD) 55 static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 1, 2); 56 static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 6); 57 #endif 58 #endif 59 60 static ulong rk3368_clk_get_rate(struct clk *clk); 61 62 /* Get pll rate by id */ 63 static uint32_t rkclk_pll_get_rate(struct rk3368_cru *cru, 64 enum rk3368_pll_id pll_id) 65 { 66 uint32_t nr, no, nf; 67 uint32_t con; 68 struct rk3368_pll *pll = &cru->pll[pll_id]; 69 70 con = readl(&pll->con3); 71 72 switch ((con & PLL_MODE_MASK) >> PLL_MODE_SHIFT) { 73 case PLL_MODE_SLOW: 74 return OSC_HZ; 75 case PLL_MODE_NORMAL: 76 con = readl(&pll->con0); 77 no = ((con & PLL_OD_MASK) >> PLL_OD_SHIFT) + 1; 78 nr = ((con & PLL_NR_MASK) >> PLL_NR_SHIFT) + 1; 79 con = readl(&pll->con1); 80 nf = ((con & PLL_NF_MASK) >> PLL_NF_SHIFT) + 1; 81 82 return (24 * nf / (nr * no)) * 1000000; 83 case PLL_MODE_DEEP_SLOW: 84 default: 85 return 32768; 86 } 87 } 88 89 #if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD) 90 static int rkclk_set_pll(struct rk3368_cru *cru, enum rk3368_pll_id pll_id, 91 const struct pll_div *div) 92 { 93 struct rk3368_pll *pll = &cru->pll[pll_id]; 94 /* All PLLs have same VCO and output frequency range restrictions*/ 95 uint vco_hz = OSC_HZ / 1000 * div->nf / div->nr * 1000; 96 uint output_hz = vco_hz / div->no; 97 98 debug("PLL at %p: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n", 99 pll, div->nf, div->nr, div->no, vco_hz, output_hz); 100 101 /* enter slow mode and reset pll */ 102 rk_clrsetreg(&pll->con3, PLL_MODE_MASK | PLL_RESET_MASK, 103 PLL_RESET << PLL_RESET_SHIFT); 104 105 rk_clrsetreg(&pll->con0, PLL_NR_MASK | PLL_OD_MASK, 106 ((div->nr - 1) << PLL_NR_SHIFT) | 107 ((div->no - 1) << PLL_OD_SHIFT)); 108 writel((div->nf - 1) << PLL_NF_SHIFT, &pll->con1); 109 /* 110 * BWADJ should be set to NF / 2 to ensure the nominal bandwidth. 111 * Compare the RK3368 TRM, section "3.6.4 PLL Bandwidth Adjustment". 112 */ 113 clrsetbits_le32(&pll->con2, PLL_BWADJ_MASK, (div->nf >> 1) - 1); 114 115 udelay(10); 116 117 /* return from reset */ 118 rk_clrreg(&pll->con3, PLL_RESET_MASK); 119 120 /* waiting for pll lock */ 121 while (!(readl(&pll->con1) & PLL_LOCK_STA)) 122 udelay(1); 123 124 rk_clrsetreg(&pll->con3, PLL_MODE_MASK, 125 PLL_MODE_NORMAL << PLL_MODE_SHIFT); 126 127 return 0; 128 } 129 #endif 130 131 #if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD) 132 static void rkclk_init(struct rk3368_cru *cru) 133 { 134 u32 apllb, aplll, dpll, cpll, gpll; 135 136 rkclk_set_pll(cru, APLLB, &apll_b_init_cfg); 137 rkclk_set_pll(cru, APLLL, &apll_l_init_cfg); 138 #if !defined(CONFIG_TPL_BUILD) 139 /* 140 * If we plan to return to the boot ROM, we can't increase the 141 * GPLL rate from the SPL stage. 142 */ 143 rkclk_set_pll(cru, GPLL, &gpll_init_cfg); 144 rkclk_set_pll(cru, CPLL, &cpll_init_cfg); 145 #endif 146 147 apllb = rkclk_pll_get_rate(cru, APLLB); 148 aplll = rkclk_pll_get_rate(cru, APLLL); 149 dpll = rkclk_pll_get_rate(cru, DPLL); 150 cpll = rkclk_pll_get_rate(cru, CPLL); 151 gpll = rkclk_pll_get_rate(cru, GPLL); 152 153 debug("%s apllb(%d) apll(%d) dpll(%d) cpll(%d) gpll(%d)\n", 154 __func__, apllb, aplll, dpll, cpll, gpll); 155 } 156 #endif 157 158 #if !IS_ENABLED(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(MMC_SUPPORT) 159 static ulong rk3368_mmc_get_clk(struct rk3368_cru *cru, uint clk_id) 160 { 161 u32 div, con, con_id, rate; 162 u32 pll_rate; 163 164 switch (clk_id) { 165 case HCLK_SDMMC: 166 con_id = 50; 167 break; 168 case HCLK_EMMC: 169 con_id = 51; 170 break; 171 case SCLK_SDIO0: 172 con_id = 48; 173 break; 174 default: 175 return -EINVAL; 176 } 177 178 con = readl(&cru->clksel_con[con_id]); 179 switch (con & MMC_PLL_SEL_MASK) { 180 case MMC_PLL_SEL_GPLL: 181 pll_rate = rkclk_pll_get_rate(cru, GPLL); 182 break; 183 case MMC_PLL_SEL_24M: 184 pll_rate = OSC_HZ; 185 break; 186 case MMC_PLL_SEL_CPLL: 187 pll_rate = rkclk_pll_get_rate(cru, CPLL); 188 break; 189 case MMC_PLL_SEL_USBPHY_480M: 190 default: 191 return -EINVAL; 192 } 193 div = (con & MMC_CLK_DIV_MASK) >> MMC_CLK_DIV_SHIFT; 194 rate = DIV_TO_RATE(pll_rate, div); 195 196 debug("%s: raw rate %d (post-divide by 2)\n", __func__, rate); 197 return rate >> 1; 198 } 199 200 static ulong rk3368_mmc_find_best_rate_and_parent(struct clk *clk, 201 ulong rate, 202 u32 *best_mux, 203 u32 *best_div) 204 { 205 int i; 206 ulong best_rate = 0; 207 const ulong MHz = 1000000; 208 const struct { 209 u32 mux; 210 ulong rate; 211 } parents[] = { 212 { .mux = MMC_PLL_SEL_CPLL, .rate = CPLL_HZ }, 213 { .mux = MMC_PLL_SEL_GPLL, .rate = GPLL_HZ }, 214 { .mux = MMC_PLL_SEL_24M, .rate = 24 * MHz } 215 }; 216 217 debug("%s: target rate %ld\n", __func__, rate); 218 for (i = 0; i < ARRAY_SIZE(parents); ++i) { 219 /* 220 * Find the largest rate no larger than the target-rate for 221 * the current parent. 222 */ 223 ulong parent_rate = parents[i].rate; 224 u32 div = DIV_ROUND_UP(parent_rate, rate); 225 u32 adj_div = div; 226 ulong new_rate = parent_rate / adj_div; 227 228 debug("%s: rate %ld, parent-mux %d, parent-rate %ld, div %d\n", 229 __func__, rate, parents[i].mux, parents[i].rate, div); 230 231 /* Skip, if not representable */ 232 if ((div - 1) > MMC_CLK_DIV_MASK) 233 continue; 234 235 /* Skip, if we already have a better (or equal) solution */ 236 if (new_rate <= best_rate) 237 continue; 238 239 /* This is our new best rate. */ 240 best_rate = new_rate; 241 *best_mux = parents[i].mux; 242 *best_div = div - 1; 243 } 244 245 debug("%s: best_mux = %x, best_div = %d, best_rate = %ld\n", 246 __func__, *best_mux, *best_div, best_rate); 247 248 return best_rate; 249 } 250 251 static ulong rk3368_mmc_set_clk(struct clk *clk, ulong rate) 252 { 253 struct rk3368_clk_priv *priv = dev_get_priv(clk->dev); 254 struct rk3368_cru *cru = priv->cru; 255 ulong clk_id = clk->id; 256 u32 con_id, mux = 0, div = 0; 257 258 /* Find the best parent and rate */ 259 rk3368_mmc_find_best_rate_and_parent(clk, rate << 1, &mux, &div); 260 261 switch (clk_id) { 262 case HCLK_SDMMC: 263 con_id = 50; 264 break; 265 case HCLK_EMMC: 266 con_id = 51; 267 break; 268 case SCLK_SDIO0: 269 con_id = 48; 270 break; 271 default: 272 return -EINVAL; 273 } 274 275 rk_clrsetreg(&cru->clksel_con[con_id], 276 MMC_PLL_SEL_MASK | MMC_CLK_DIV_MASK, 277 mux | div); 278 279 return rk3368_mmc_get_clk(cru, clk_id); 280 } 281 #endif 282 283 #if IS_ENABLED(CONFIG_TPL_BUILD) 284 static ulong rk3368_ddr_set_clk(struct rk3368_cru *cru, ulong set_rate) 285 { 286 const struct pll_div *dpll_cfg = NULL; 287 const ulong MHz = 1000000; 288 289 /* Fout = ((Fin /NR) * NF )/ NO */ 290 static const struct pll_div dpll_1200 = PLL_DIVISORS(1200 * MHz, 1, 1); 291 static const struct pll_div dpll_1332 = PLL_DIVISORS(1332 * MHz, 2, 1); 292 static const struct pll_div dpll_1600 = PLL_DIVISORS(1600 * MHz, 3, 2); 293 294 switch (set_rate) { 295 case 1200*MHz: 296 dpll_cfg = &dpll_1200; 297 break; 298 case 1332*MHz: 299 dpll_cfg = &dpll_1332; 300 break; 301 case 1600*MHz: 302 dpll_cfg = &dpll_1600; 303 break; 304 default: 305 pr_err("Unsupported SDRAM frequency!,%ld\n", set_rate); 306 } 307 rkclk_set_pll(cru, DPLL, dpll_cfg); 308 309 return set_rate; 310 } 311 #endif 312 313 #if CONFIG_IS_ENABLED(GMAC_ROCKCHIP) 314 static ulong rk3368_gmac_set_clk(struct rk3368_cru *cru, ulong set_rate) 315 { 316 ulong ret; 317 318 /* 319 * The gmac clock can be derived either from an external clock 320 * or can be generated from internally by a divider from SCLK_MAC. 321 */ 322 if (readl(&cru->clksel_con[43]) & GMAC_MUX_SEL_EXTCLK) { 323 /* An external clock will always generate the right rate... */ 324 ret = set_rate; 325 } else { 326 u32 con = readl(&cru->clksel_con[43]); 327 ulong pll_rate; 328 u8 div; 329 330 if (((con >> GMAC_PLL_SHIFT) & GMAC_PLL_MASK) == 331 GMAC_PLL_SELECT_GENERAL) 332 pll_rate = GPLL_HZ; 333 else if (((con >> GMAC_PLL_SHIFT) & GMAC_PLL_MASK) == 334 GMAC_PLL_SELECT_CODEC) 335 pll_rate = CPLL_HZ; 336 else 337 /* CPLL is not set */ 338 return -EPERM; 339 340 div = DIV_ROUND_UP(pll_rate, set_rate) - 1; 341 if (div <= 0x1f) 342 rk_clrsetreg(&cru->clksel_con[43], GMAC_DIV_CON_MASK, 343 div << GMAC_DIV_CON_SHIFT); 344 else 345 debug("Unsupported div for gmac:%d\n", div); 346 347 return DIV_TO_RATE(pll_rate, div); 348 } 349 350 return ret; 351 } 352 #endif 353 354 /* 355 * RK3368 SPI clocks have a common divider-width (7 bits) and a single bit 356 * to select either CPLL or GPLL as the clock-parent. The location within 357 * the enclosing CLKSEL_CON (i.e. div_shift and sel_shift) are variable. 358 */ 359 360 struct spi_clkreg { 361 uint8_t reg; /* CLKSEL_CON[reg] register in CRU */ 362 uint8_t div_shift; 363 uint8_t sel_shift; 364 }; 365 366 /* 367 * The entries are numbered relative to their offset from SCLK_SPI0. 368 */ 369 static const struct spi_clkreg spi_clkregs[] = { 370 [0] = { .reg = 45, .div_shift = 0, .sel_shift = 7, }, 371 [1] = { .reg = 45, .div_shift = 8, .sel_shift = 15, }, 372 [2] = { .reg = 46, .div_shift = 8, .sel_shift = 15, }, 373 }; 374 375 static inline u32 extract_bits(u32 val, unsigned width, unsigned shift) 376 { 377 return (val >> shift) & ((1 << width) - 1); 378 } 379 380 static ulong rk3368_spi_get_clk(struct rk3368_cru *cru, ulong clk_id) 381 { 382 const struct spi_clkreg *spiclk = NULL; 383 u32 div, val; 384 385 switch (clk_id) { 386 case SCLK_SPI0 ... SCLK_SPI2: 387 spiclk = &spi_clkregs[clk_id - SCLK_SPI0]; 388 break; 389 390 default: 391 pr_err("%s: SPI clk-id %ld not supported\n", __func__, clk_id); 392 return -EINVAL; 393 } 394 395 val = readl(&cru->clksel_con[spiclk->reg]); 396 div = extract_bits(val, 7, spiclk->div_shift); 397 398 debug("%s: div 0x%x\n", __func__, div); 399 return DIV_TO_RATE(GPLL_HZ, div); 400 } 401 402 static ulong rk3368_spi_set_clk(struct rk3368_cru *cru, ulong clk_id, uint hz) 403 { 404 const struct spi_clkreg *spiclk = NULL; 405 int src_clk_div; 406 407 src_clk_div = DIV_ROUND_UP(GPLL_HZ, hz); 408 assert(src_clk_div < 127); 409 410 switch (clk_id) { 411 case SCLK_SPI0 ... SCLK_SPI2: 412 spiclk = &spi_clkregs[clk_id - SCLK_SPI0]; 413 break; 414 415 default: 416 pr_err("%s: SPI clk-id %ld not supported\n", __func__, clk_id); 417 return -EINVAL; 418 } 419 420 rk_clrsetreg(&cru->clksel_con[spiclk->reg], 421 ((0x7f << spiclk->div_shift) | 422 (0x1 << spiclk->sel_shift)), 423 ((src_clk_div << spiclk->div_shift) | 424 (1 << spiclk->sel_shift))); 425 426 return rk3368_spi_get_clk(cru, clk_id); 427 } 428 429 static ulong rk3368_saradc_get_clk(struct rk3368_cru *cru) 430 { 431 u32 div, val; 432 433 val = readl(&cru->clksel_con[25]); 434 div = bitfield_extract(val, CLK_SARADC_DIV_CON_SHIFT, 435 CLK_SARADC_DIV_CON_WIDTH); 436 437 return DIV_TO_RATE(OSC_HZ, div); 438 } 439 440 static ulong rk3368_saradc_set_clk(struct rk3368_cru *cru, uint hz) 441 { 442 int src_clk_div; 443 444 src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1; 445 assert(src_clk_div < 128); 446 447 rk_clrsetreg(&cru->clksel_con[25], 448 CLK_SARADC_DIV_CON_MASK, 449 src_clk_div << CLK_SARADC_DIV_CON_SHIFT); 450 451 return rk3368_saradc_get_clk(cru); 452 } 453 454 static ulong rk3368_clk_get_rate(struct clk *clk) 455 { 456 struct rk3368_clk_priv *priv = dev_get_priv(clk->dev); 457 ulong rate = 0; 458 459 debug("%s: id %ld\n", __func__, clk->id); 460 switch (clk->id) { 461 case PLL_CPLL: 462 rate = rkclk_pll_get_rate(priv->cru, CPLL); 463 break; 464 case PLL_GPLL: 465 rate = rkclk_pll_get_rate(priv->cru, GPLL); 466 break; 467 case SCLK_SPI0 ... SCLK_SPI2: 468 rate = rk3368_spi_get_clk(priv->cru, clk->id); 469 break; 470 #if !IS_ENABLED(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(MMC_SUPPORT) 471 case HCLK_SDMMC: 472 case HCLK_EMMC: 473 rate = rk3368_mmc_get_clk(priv->cru, clk->id); 474 break; 475 #endif 476 case SCLK_SARADC: 477 rate = rk3368_saradc_get_clk(priv->cru); 478 break; 479 default: 480 return -ENOENT; 481 } 482 483 return rate; 484 } 485 486 static ulong rk3368_clk_set_rate(struct clk *clk, ulong rate) 487 { 488 __maybe_unused struct rk3368_clk_priv *priv = dev_get_priv(clk->dev); 489 ulong ret = 0; 490 491 debug("%s id:%ld rate:%ld\n", __func__, clk->id, rate); 492 switch (clk->id) { 493 case SCLK_SPI0 ... SCLK_SPI2: 494 ret = rk3368_spi_set_clk(priv->cru, clk->id, rate); 495 break; 496 #if IS_ENABLED(CONFIG_TPL_BUILD) 497 case CLK_DDR: 498 ret = rk3368_ddr_set_clk(priv->cru, rate); 499 break; 500 #endif 501 #if !IS_ENABLED(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(MMC_SUPPORT) 502 case HCLK_SDMMC: 503 case HCLK_EMMC: 504 ret = rk3368_mmc_set_clk(clk, rate); 505 break; 506 #endif 507 #if CONFIG_IS_ENABLED(GMAC_ROCKCHIP) 508 case SCLK_MAC: 509 /* select the external clock */ 510 ret = rk3368_gmac_set_clk(priv->cru, rate); 511 break; 512 #endif 513 case SCLK_SARADC: 514 ret = rk3368_saradc_set_clk(priv->cru, rate); 515 break; 516 default: 517 return -ENOENT; 518 } 519 520 return ret; 521 } 522 523 static int __maybe_unused rk3368_gmac_set_parent(struct clk *clk, struct clk *parent) 524 { 525 struct rk3368_clk_priv *priv = dev_get_priv(clk->dev); 526 struct rk3368_cru *cru = priv->cru; 527 const char *clock_output_name; 528 int ret; 529 530 /* 531 * If the requested parent is in the same clock-controller and 532 * the id is SCLK_MAC ("sclk_mac"), switch to the internal 533 * clock. 534 */ 535 if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC)) { 536 debug("%s: switching GAMC to SCLK_MAC\n", __func__); 537 rk_clrreg(&cru->clksel_con[43], GMAC_MUX_SEL_EXTCLK); 538 return 0; 539 } 540 541 /* 542 * Otherwise, we need to check the clock-output-names of the 543 * requested parent to see if the requested id is "ext_gmac". 544 */ 545 ret = dev_read_string_index(parent->dev, "clock-output-names", 546 parent->id, &clock_output_name); 547 if (ret < 0) 548 return -ENODATA; 549 550 /* If this is "ext_gmac", switch to the external clock input */ 551 if (!strcmp(clock_output_name, "ext_gmac")) { 552 debug("%s: switching GMAC to external clock\n", __func__); 553 rk_setreg(&cru->clksel_con[43], GMAC_MUX_SEL_EXTCLK); 554 return 0; 555 } 556 557 return -EINVAL; 558 } 559 560 static int __maybe_unused rk3368_clk_set_parent(struct clk *clk, struct clk *parent) 561 { 562 switch (clk->id) { 563 case SCLK_MAC: 564 return rk3368_gmac_set_parent(clk, parent); 565 } 566 567 debug("%s: unsupported clk %ld\n", __func__, clk->id); 568 return -ENOENT; 569 } 570 571 static struct clk_ops rk3368_clk_ops = { 572 .get_rate = rk3368_clk_get_rate, 573 .set_rate = rk3368_clk_set_rate, 574 #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) 575 .set_parent = rk3368_clk_set_parent, 576 #endif 577 }; 578 579 static int rk3368_clk_probe(struct udevice *dev) 580 { 581 struct rk3368_clk_priv __maybe_unused *priv = dev_get_priv(dev); 582 #if CONFIG_IS_ENABLED(OF_PLATDATA) 583 struct rk3368_clk_plat *plat = dev_get_platdata(dev); 584 585 priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]); 586 #endif 587 #if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD) 588 rkclk_init(priv->cru); 589 #endif 590 591 return 0; 592 } 593 594 static int rk3368_clk_ofdata_to_platdata(struct udevice *dev) 595 { 596 #if !CONFIG_IS_ENABLED(OF_PLATDATA) 597 struct rk3368_clk_priv *priv = dev_get_priv(dev); 598 599 priv->cru = dev_read_addr_ptr(dev); 600 #endif 601 602 return 0; 603 } 604 605 static int rk3368_clk_bind(struct udevice *dev) 606 { 607 int ret; 608 struct udevice *sys_child; 609 struct sysreset_reg *priv; 610 611 /* The reset driver does not have a device node, so bind it here */ 612 ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", 613 &sys_child); 614 if (ret) { 615 debug("Warning: No sysreset driver: ret=%d\n", ret); 616 } else { 617 priv = malloc(sizeof(struct sysreset_reg)); 618 priv->glb_srst_fst_value = offsetof(struct rk3368_cru, 619 glb_srst_fst_val); 620 priv->glb_srst_snd_value = offsetof(struct rk3368_cru, 621 glb_srst_snd_val); 622 sys_child->priv = priv; 623 } 624 625 #if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP) 626 ret = offsetof(struct rk3368_cru, softrst_con[0]); 627 ret = rockchip_reset_bind(dev, ret, 15); 628 if (ret) 629 debug("Warning: software reset driver bind faile\n"); 630 #endif 631 632 return ret; 633 } 634 635 static const struct udevice_id rk3368_clk_ids[] = { 636 { .compatible = "rockchip,rk3368-cru" }, 637 { } 638 }; 639 640 U_BOOT_DRIVER(rockchip_rk3368_cru) = { 641 .name = "rockchip_rk3368_cru", 642 .id = UCLASS_CLK, 643 .of_match = rk3368_clk_ids, 644 .priv_auto_alloc_size = sizeof(struct rk3368_clk_priv), 645 #if CONFIG_IS_ENABLED(OF_PLATDATA) 646 .platdata_auto_alloc_size = sizeof(struct rk3368_clk_plat), 647 #endif 648 .ofdata_to_platdata = rk3368_clk_ofdata_to_platdata, 649 .ops = &rk3368_clk_ops, 650 .bind = rk3368_clk_bind, 651 .probe = rk3368_clk_probe, 652 }; 653