Home | History | Annotate | Download | only in aspeed
      1 // SPDX-License-Identifier: GPL-2.0
      2 /*
      3  * (C) Copyright 2016 Google, Inc
      4  */
      5 
      6 #include <common.h>
      7 #include <clk-uclass.h>
      8 #include <dm.h>
      9 #include <asm/io.h>
     10 #include <asm/arch/scu_ast2500.h>
     11 #include <dm/lists.h>
     12 #include <dt-bindings/clock/ast2500-scu.h>
     13 
     14 /*
     15  * MAC Clock Delay settings, taken from Aspeed SDK
     16  */
     17 #define RGMII_TXCLK_ODLY		8
     18 #define RMII_RXCLK_IDLY		2
     19 
     20 /*
     21  * TGMII Clock Duty constants, taken from Aspeed SDK
     22  */
     23 #define RGMII2_TXCK_DUTY	0x66
     24 #define RGMII1_TXCK_DUTY	0x64
     25 
     26 #define D2PLL_DEFAULT_RATE	(250 * 1000 * 1000)
     27 
     28 DECLARE_GLOBAL_DATA_PTR;
     29 
     30 /*
     31  * Clock divider/multiplier configuration struct.
     32  * For H-PLL and M-PLL the formula is
     33  * (Output Frequency) = CLKIN * ((M + 1) / (N + 1)) / (P + 1)
     34  * M - Numerator
     35  * N - Denumerator
     36  * P - Post Divider
     37  * They have the same layout in their control register.
     38  *
     39  * D-PLL and D2-PLL have extra divider (OD + 1), which is not
     40  * yet needed and ignored by clock configurations.
     41  */
     42 struct ast2500_div_config {
     43 	unsigned int num;
     44 	unsigned int denum;
     45 	unsigned int post_div;
     46 };
     47 
     48 /*
     49  * Get the rate of the M-PLL clock from input clock frequency and
     50  * the value of the M-PLL Parameter Register.
     51  */
     52 static ulong ast2500_get_mpll_rate(ulong clkin, u32 mpll_reg)
     53 {
     54 	const ulong num = (mpll_reg & SCU_MPLL_NUM_MASK) >> SCU_MPLL_NUM_SHIFT;
     55 	const ulong denum = (mpll_reg & SCU_MPLL_DENUM_MASK)
     56 			>> SCU_MPLL_DENUM_SHIFT;
     57 	const ulong post_div = (mpll_reg & SCU_MPLL_POST_MASK)
     58 			>> SCU_MPLL_POST_SHIFT;
     59 
     60 	return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1);
     61 }
     62 
     63 /*
     64  * Get the rate of the H-PLL clock from input clock frequency and
     65  * the value of the H-PLL Parameter Register.
     66  */
     67 static ulong ast2500_get_hpll_rate(ulong clkin, u32 hpll_reg)
     68 {
     69 	const ulong num = (hpll_reg & SCU_HPLL_NUM_MASK) >> SCU_HPLL_NUM_SHIFT;
     70 	const ulong denum = (hpll_reg & SCU_HPLL_DENUM_MASK)
     71 			>> SCU_HPLL_DENUM_SHIFT;
     72 	const ulong post_div = (hpll_reg & SCU_HPLL_POST_MASK)
     73 			>> SCU_HPLL_POST_SHIFT;
     74 
     75 	return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1);
     76 }
     77 
     78 static ulong ast2500_get_clkin(struct ast2500_scu *scu)
     79 {
     80 	return readl(&scu->hwstrap) & SCU_HWSTRAP_CLKIN_25MHZ
     81 			? 25 * 1000 * 1000 : 24 * 1000 * 1000;
     82 }
     83 
     84 /**
     85  * Get current rate or uart clock
     86  *
     87  * @scu SCU registers
     88  * @uart_index UART index, 1-5
     89  *
     90  * @return current setting for uart clock rate
     91  */
     92 static ulong ast2500_get_uart_clk_rate(struct ast2500_scu *scu, int uart_index)
     93 {
     94 	/*
     95 	 * ast2500 datasheet is very confusing when it comes to UART clocks,
     96 	 * especially when CLKIN = 25 MHz. The settings are in
     97 	 * different registers and it is unclear how they interact.
     98 	 *
     99 	 * This has only been tested with default settings and CLKIN = 24 MHz.
    100 	 */
    101 	ulong uart_clkin;
    102 
    103 	if (readl(&scu->misc_ctrl2) &
    104 	    (1 << (uart_index - 1 + SCU_MISC2_UARTCLK_SHIFT)))
    105 		uart_clkin = 192 * 1000 * 1000;
    106 	else
    107 		uart_clkin = 24 * 1000 * 1000;
    108 
    109 	if (readl(&scu->misc_ctrl1) & SCU_MISC_UARTCLK_DIV13)
    110 		uart_clkin /= 13;
    111 
    112 	return uart_clkin;
    113 }
    114 
    115 static ulong ast2500_clk_get_rate(struct clk *clk)
    116 {
    117 	struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
    118 	ulong clkin = ast2500_get_clkin(priv->scu);
    119 	ulong rate;
    120 
    121 	switch (clk->id) {
    122 	case PLL_HPLL:
    123 	case ARMCLK:
    124 		/*
    125 		 * This ignores dynamic/static slowdown of ARMCLK and may
    126 		 * be inaccurate.
    127 		 */
    128 		rate = ast2500_get_hpll_rate(clkin,
    129 					     readl(&priv->scu->h_pll_param));
    130 		break;
    131 	case MCLK_DDR:
    132 		rate = ast2500_get_mpll_rate(clkin,
    133 					     readl(&priv->scu->m_pll_param));
    134 		break;
    135 	case BCLK_PCLK:
    136 		{
    137 			ulong apb_div = 4 + 4 * ((readl(&priv->scu->clk_sel1)
    138 						  & SCU_PCLK_DIV_MASK)
    139 						 >> SCU_PCLK_DIV_SHIFT);
    140 			rate = ast2500_get_hpll_rate(clkin,
    141 						     readl(&priv->
    142 							   scu->h_pll_param));
    143 			rate = rate / apb_div;
    144 		}
    145 		break;
    146 	case PCLK_UART1:
    147 		rate = ast2500_get_uart_clk_rate(priv->scu, 1);
    148 		break;
    149 	case PCLK_UART2:
    150 		rate = ast2500_get_uart_clk_rate(priv->scu, 2);
    151 		break;
    152 	case PCLK_UART3:
    153 		rate = ast2500_get_uart_clk_rate(priv->scu, 3);
    154 		break;
    155 	case PCLK_UART4:
    156 		rate = ast2500_get_uart_clk_rate(priv->scu, 4);
    157 		break;
    158 	case PCLK_UART5:
    159 		rate = ast2500_get_uart_clk_rate(priv->scu, 5);
    160 		break;
    161 	default:
    162 		return -ENOENT;
    163 	}
    164 
    165 	return rate;
    166 }
    167 
    168 /*
    169  * @input_rate - the rate of input clock in Hz
    170  * @requested_rate - desired output rate in Hz
    171  * @div - this is an IN/OUT parameter, at input all fields of the config
    172  * need to be set to their maximum allowed values.
    173  * The result (the best config we could find), would also be returned
    174  * in this structure.
    175  *
    176  * @return The clock rate, when the resulting div_config is used.
    177  */
    178 static ulong ast2500_calc_clock_config(ulong input_rate, ulong requested_rate,
    179 				       struct ast2500_div_config *cfg)
    180 {
    181 	/*
    182 	 * The assumption is that kHz precision is good enough and
    183 	 * also enough to avoid overflow when multiplying.
    184 	 */
    185 	const ulong input_rate_khz = input_rate / 1000;
    186 	const ulong rate_khz = requested_rate / 1000;
    187 	const struct ast2500_div_config max_vals = *cfg;
    188 	struct ast2500_div_config it = { 0, 0, 0 };
    189 	ulong delta = rate_khz;
    190 	ulong new_rate_khz = 0;
    191 
    192 	for (; it.denum <= max_vals.denum; ++it.denum) {
    193 		for (it.post_div = 0; it.post_div <= max_vals.post_div;
    194 		     ++it.post_div) {
    195 			it.num = (rate_khz * (it.post_div + 1) / input_rate_khz)
    196 			    * (it.denum + 1);
    197 			if (it.num > max_vals.num)
    198 				continue;
    199 
    200 			new_rate_khz = (input_rate_khz
    201 					* ((it.num + 1) / (it.denum + 1)))
    202 			    / (it.post_div + 1);
    203 
    204 			/* Keep the rate below requested one. */
    205 			if (new_rate_khz > rate_khz)
    206 				continue;
    207 
    208 			if (new_rate_khz - rate_khz < delta) {
    209 				delta = new_rate_khz - rate_khz;
    210 				*cfg = it;
    211 				if (delta == 0)
    212 					return new_rate_khz * 1000;
    213 			}
    214 		}
    215 	}
    216 
    217 	return new_rate_khz * 1000;
    218 }
    219 
    220 static ulong ast2500_configure_ddr(struct ast2500_scu *scu, ulong rate)
    221 {
    222 	ulong clkin = ast2500_get_clkin(scu);
    223 	u32 mpll_reg;
    224 	struct ast2500_div_config div_cfg = {
    225 		.num = (SCU_MPLL_NUM_MASK >> SCU_MPLL_NUM_SHIFT),
    226 		.denum = (SCU_MPLL_DENUM_MASK >> SCU_MPLL_DENUM_SHIFT),
    227 		.post_div = (SCU_MPLL_POST_MASK >> SCU_MPLL_POST_SHIFT),
    228 	};
    229 
    230 	ast2500_calc_clock_config(clkin, rate, &div_cfg);
    231 
    232 	mpll_reg = readl(&scu->m_pll_param);
    233 	mpll_reg &= ~(SCU_MPLL_POST_MASK | SCU_MPLL_NUM_MASK
    234 		      | SCU_MPLL_DENUM_MASK);
    235 	mpll_reg |= (div_cfg.post_div << SCU_MPLL_POST_SHIFT)
    236 	    | (div_cfg.num << SCU_MPLL_NUM_SHIFT)
    237 	    | (div_cfg.denum << SCU_MPLL_DENUM_SHIFT);
    238 
    239 	ast_scu_unlock(scu);
    240 	writel(mpll_reg, &scu->m_pll_param);
    241 	ast_scu_lock(scu);
    242 
    243 	return ast2500_get_mpll_rate(clkin, mpll_reg);
    244 }
    245 
    246 static ulong ast2500_configure_mac(struct ast2500_scu *scu, int index)
    247 {
    248 	ulong clkin = ast2500_get_clkin(scu);
    249 	ulong hpll_rate = ast2500_get_hpll_rate(clkin,
    250 						readl(&scu->h_pll_param));
    251 	ulong required_rate;
    252 	u32 hwstrap;
    253 	u32 divisor;
    254 	u32 reset_bit;
    255 	u32 clkstop_bit;
    256 
    257 	/*
    258 	 * According to data sheet, for 10/100 mode the MAC clock frequency
    259 	 * should be at least 25MHz and for 1000 mode at least 100MHz
    260 	 */
    261 	hwstrap = readl(&scu->hwstrap);
    262 	if (hwstrap & (SCU_HWSTRAP_MAC1_RGMII | SCU_HWSTRAP_MAC2_RGMII))
    263 		required_rate = 100 * 1000 * 1000;
    264 	else
    265 		required_rate = 25 * 1000 * 1000;
    266 
    267 	divisor = hpll_rate / required_rate;
    268 
    269 	if (divisor < 4) {
    270 		/* Clock can't run fast enough, but let's try anyway */
    271 		debug("MAC clock too slow\n");
    272 		divisor = 4;
    273 	} else if (divisor > 16) {
    274 		/* Can't slow down the clock enough, but let's try anyway */
    275 		debug("MAC clock too fast\n");
    276 		divisor = 16;
    277 	}
    278 
    279 	switch (index) {
    280 	case 1:
    281 		reset_bit = SCU_SYSRESET_MAC1;
    282 		clkstop_bit = SCU_CLKSTOP_MAC1;
    283 		break;
    284 	case 2:
    285 		reset_bit = SCU_SYSRESET_MAC2;
    286 		clkstop_bit = SCU_CLKSTOP_MAC2;
    287 		break;
    288 	default:
    289 		return -EINVAL;
    290 	}
    291 
    292 	ast_scu_unlock(scu);
    293 	clrsetbits_le32(&scu->clk_sel1, SCU_MACCLK_MASK,
    294 			((divisor - 2) / 2) << SCU_MACCLK_SHIFT);
    295 
    296 	/*
    297 	 * Disable MAC, start its clock and re-enable it.
    298 	 * The procedure and the delays (100us & 10ms) are
    299 	 * specified in the datasheet.
    300 	 */
    301 	setbits_le32(&scu->sysreset_ctrl1, reset_bit);
    302 	udelay(100);
    303 	clrbits_le32(&scu->clk_stop_ctrl1, clkstop_bit);
    304 	mdelay(10);
    305 	clrbits_le32(&scu->sysreset_ctrl1, reset_bit);
    306 
    307 	writel((RGMII2_TXCK_DUTY << SCU_CLKDUTY_RGMII2TXCK_SHIFT)
    308 	       | (RGMII1_TXCK_DUTY << SCU_CLKDUTY_RGMII1TXCK_SHIFT),
    309 	       &scu->clk_duty_sel);
    310 
    311 	ast_scu_lock(scu);
    312 
    313 	return required_rate;
    314 }
    315 
    316 static ulong ast2500_configure_d2pll(struct ast2500_scu *scu, ulong rate)
    317 {
    318 	/*
    319 	 * The values and the meaning of the next three
    320 	 * parameters are undocumented. Taken from Aspeed SDK.
    321 	 */
    322 	const u32 d2_pll_ext_param = 0x2c;
    323 	const u32 d2_pll_sip = 0x11;
    324 	const u32 d2_pll_sic = 0x18;
    325 	u32 clk_delay_settings =
    326 	    (RMII_RXCLK_IDLY << SCU_MICDS_MAC1RMII_RDLY_SHIFT)
    327 	    | (RMII_RXCLK_IDLY << SCU_MICDS_MAC2RMII_RDLY_SHIFT)
    328 	    | (RGMII_TXCLK_ODLY << SCU_MICDS_MAC1RGMII_TXDLY_SHIFT)
    329 	    | (RGMII_TXCLK_ODLY << SCU_MICDS_MAC2RGMII_TXDLY_SHIFT);
    330 	struct ast2500_div_config div_cfg = {
    331 		.num = SCU_D2PLL_NUM_MASK >> SCU_D2PLL_NUM_SHIFT,
    332 		.denum = SCU_D2PLL_DENUM_MASK >> SCU_D2PLL_DENUM_SHIFT,
    333 		.post_div = SCU_D2PLL_POST_MASK >> SCU_D2PLL_POST_SHIFT,
    334 	};
    335 	ulong clkin = ast2500_get_clkin(scu);
    336 	ulong new_rate;
    337 
    338 	ast_scu_unlock(scu);
    339 	writel((d2_pll_ext_param << SCU_D2PLL_EXT1_PARAM_SHIFT)
    340 	       | SCU_D2PLL_EXT1_OFF
    341 	       | SCU_D2PLL_EXT1_RESET, &scu->d2_pll_ext_param[0]);
    342 
    343 	/*
    344 	 * Select USB2.0 port1 PHY clock as a clock source for GCRT.
    345 	 * This would disconnect it from D2-PLL.
    346 	 */
    347 	clrsetbits_le32(&scu->misc_ctrl1, SCU_MISC_D2PLL_OFF,
    348 			SCU_MISC_GCRT_USB20CLK);
    349 
    350 	new_rate = ast2500_calc_clock_config(clkin, rate, &div_cfg);
    351 	writel((d2_pll_sip << SCU_D2PLL_SIP_SHIFT)
    352 	       | (d2_pll_sic << SCU_D2PLL_SIC_SHIFT)
    353 	       | (div_cfg.num << SCU_D2PLL_NUM_SHIFT)
    354 	       | (div_cfg.denum << SCU_D2PLL_DENUM_SHIFT)
    355 	       | (div_cfg.post_div << SCU_D2PLL_POST_SHIFT),
    356 	       &scu->d2_pll_param);
    357 
    358 	clrbits_le32(&scu->d2_pll_ext_param[0],
    359 		     SCU_D2PLL_EXT1_OFF | SCU_D2PLL_EXT1_RESET);
    360 
    361 	clrsetbits_le32(&scu->misc_ctrl2,
    362 			SCU_MISC2_RGMII_HPLL | SCU_MISC2_RMII_MPLL
    363 			| SCU_MISC2_RGMII_CLKDIV_MASK |
    364 			SCU_MISC2_RMII_CLKDIV_MASK,
    365 			(4 << SCU_MISC2_RMII_CLKDIV_SHIFT));
    366 
    367 	writel(clk_delay_settings | SCU_MICDS_RGMIIPLL, &scu->mac_clk_delay);
    368 	writel(clk_delay_settings, &scu->mac_clk_delay_100M);
    369 	writel(clk_delay_settings, &scu->mac_clk_delay_10M);
    370 
    371 	ast_scu_lock(scu);
    372 
    373 	return new_rate;
    374 }
    375 
    376 static ulong ast2500_clk_set_rate(struct clk *clk, ulong rate)
    377 {
    378 	struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
    379 
    380 	ulong new_rate;
    381 	switch (clk->id) {
    382 	case PLL_MPLL:
    383 	case MCLK_DDR:
    384 		new_rate = ast2500_configure_ddr(priv->scu, rate);
    385 		break;
    386 	case PLL_D2PLL:
    387 		new_rate = ast2500_configure_d2pll(priv->scu, rate);
    388 		break;
    389 	default:
    390 		return -ENOENT;
    391 	}
    392 
    393 	return new_rate;
    394 }
    395 
    396 static int ast2500_clk_enable(struct clk *clk)
    397 {
    398 	struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
    399 
    400 	switch (clk->id) {
    401 	/*
    402 	 * For MAC clocks the clock rate is
    403 	 * configured based on whether RGMII or RMII mode has been selected
    404 	 * through hardware strapping.
    405 	 */
    406 	case PCLK_MAC1:
    407 		ast2500_configure_mac(priv->scu, 1);
    408 		break;
    409 	case PCLK_MAC2:
    410 		ast2500_configure_mac(priv->scu, 2);
    411 		break;
    412 	case PLL_D2PLL:
    413 		ast2500_configure_d2pll(priv->scu, D2PLL_DEFAULT_RATE);
    414 	default:
    415 		return -ENOENT;
    416 	}
    417 
    418 	return 0;
    419 }
    420 
    421 struct clk_ops ast2500_clk_ops = {
    422 	.get_rate = ast2500_clk_get_rate,
    423 	.set_rate = ast2500_clk_set_rate,
    424 	.enable = ast2500_clk_enable,
    425 };
    426 
    427 static int ast2500_clk_probe(struct udevice *dev)
    428 {
    429 	struct ast2500_clk_priv *priv = dev_get_priv(dev);
    430 
    431 	priv->scu = devfdt_get_addr_ptr(dev);
    432 	if (IS_ERR(priv->scu))
    433 		return PTR_ERR(priv->scu);
    434 
    435 	return 0;
    436 }
    437 
    438 static int ast2500_clk_bind(struct udevice *dev)
    439 {
    440 	int ret;
    441 
    442 	/* The reset driver does not have a device node, so bind it here */
    443 	ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev);
    444 	if (ret)
    445 		debug("Warning: No reset driver: ret=%d\n", ret);
    446 
    447 	return 0;
    448 }
    449 
    450 static const struct udevice_id ast2500_clk_ids[] = {
    451 	{ .compatible = "aspeed,ast2500-scu" },
    452 	{ }
    453 };
    454 
    455 U_BOOT_DRIVER(aspeed_ast2500_scu) = {
    456 	.name		= "aspeed_ast2500_scu",
    457 	.id		= UCLASS_CLK,
    458 	.of_match	= ast2500_clk_ids,
    459 	.priv_auto_alloc_size = sizeof(struct ast2500_clk_priv),
    460 	.ops		= &ast2500_clk_ops,
    461 	.bind		= ast2500_clk_bind,
    462 	.probe		= ast2500_clk_probe,
    463 };
    464