1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2/* 3 * Copyright (C) 2020 BayLibre, SAS. 4 * Author: Neil Armstrong <narmstrong@baylibre.com> 5 * Copyright (C) 2014 Amlogic, Inc. 6 * 7 * This PWM is only a set of Gates, Dividers and Counters: 8 * PWM output is achieved by calculating a clock that permits calculating 9 * two periods (low and high). The counter then has to be set to switch after 10 * N cycles for the first half period. 11 * The hardware has no "polarity" setting. This driver reverses the period 12 * cycles (the low length is inverted with the high length) for 13 * PWM_POLARITY_INVERSED. 14 * Setting the polarity will disable and re-enable the PWM output. 15 * Disabling the PWM stops the output immediately (without waiting for the 16 * current period to complete first). 17 */ 18 19#include <clk.h> 20#include <div64.h> 21#include <dm.h> 22#include <pwm.h> 23#include <regmap.h> 24#include <linux/io.h> 25#include <linux/math64.h> 26#include <linux/bitfield.h> 27#include <linux/clk-provider.h> 28#include <linux/time.h> 29 30#define REG_PWM_A 0x0 31#define REG_PWM_B 0x4 32#define PWM_LOW_MASK GENMASK(15, 0) 33#define PWM_HIGH_MASK GENMASK(31, 16) 34 35#define REG_MISC_AB 0x8 36#define MISC_B_CLK_EN BIT(23) 37#define MISC_A_CLK_EN BIT(15) 38#define MISC_CLK_DIV_MASK 0x7f 39#define MISC_B_CLK_DIV_SHIFT 16 40#define MISC_A_CLK_DIV_SHIFT 8 41#define MISC_B_CLK_SEL_SHIFT 6 42#define MISC_A_CLK_SEL_SHIFT 4 43#define MISC_CLK_SEL_MASK 0x3 44#define MISC_B_EN BIT(1) 45#define MISC_A_EN BIT(0) 46 47#define MESON_NUM_PWMS 2 48 49static struct meson_pwm_channel_data { 50 u8 reg_offset; 51 u8 clk_sel_shift; 52 u8 clk_div_shift; 53 u32 clk_en_mask; 54 u32 pwm_en_mask; 55} meson_pwm_per_channel_data[MESON_NUM_PWMS] = { 56 { 57 .reg_offset = REG_PWM_A, 58 .clk_sel_shift = MISC_A_CLK_SEL_SHIFT, 59 .clk_div_shift = MISC_A_CLK_DIV_SHIFT, 60 .clk_en_mask = MISC_A_CLK_EN, 61 .pwm_en_mask = MISC_A_EN, 62 }, 63 { 64 .reg_offset = REG_PWM_B, 65 .clk_sel_shift = MISC_B_CLK_SEL_SHIFT, 66 .clk_div_shift = MISC_B_CLK_DIV_SHIFT, 67 .clk_en_mask = MISC_B_CLK_EN, 68 .pwm_en_mask = MISC_B_EN, 69 } 70}; 71 72struct meson_pwm_channel { 73 unsigned int hi; 74 unsigned int lo; 75 u8 pre_div; 76 uint period_ns; 77 uint duty_ns; 78 bool configured; 79 bool enabled; 80 bool polarity; 81 struct clk clk; 82}; 83 84struct meson_pwm_data { 85 const long *parent_ids; 86 unsigned int num_parents; 87}; 88 89struct meson_pwm { 90 const struct meson_pwm_data *data; 91 struct meson_pwm_channel channels[MESON_NUM_PWMS]; 92 void __iomem *base; 93}; 94 95static int meson_pwm_set_enable(struct udevice *dev, uint channel, bool enable); 96 97static int meson_pwm_set_config(struct udevice *dev, uint channeln, 98 uint period_ns, uint duty_ns) 99{ 100 struct meson_pwm *priv = dev_get_priv(dev); 101 struct meson_pwm_channel *channel; 102 struct meson_pwm_channel_data *channel_data; 103 unsigned int duty, period, pre_div, cnt, duty_cnt; 104 unsigned long fin_freq; 105 106 if (channeln >= MESON_NUM_PWMS) 107 return -ENODEV; 108 109 channel = &priv->channels[channeln]; 110 channel_data = &meson_pwm_per_channel_data[channeln]; 111 112 period = period_ns; 113 if (channel->polarity) 114 duty = period_ns - duty_ns; 115 else 116 duty = duty_ns; 117 118 debug("%s%d: polarity %s duty %d period %d\n", __func__, channeln, 119 channel->polarity ? "true" : "false", duty, period); 120 121 fin_freq = clk_get_rate(&channel->clk); 122 if (fin_freq == 0) { 123 printf("%s%d: invalid source clock frequency\n", __func__, channeln); 124 return -EINVAL; 125 } 126 127 debug("%s%d: fin_freq: %lu Hz\n", __func__, channeln, fin_freq); 128 129 pre_div = div64_u64(fin_freq * (u64)period, NSEC_PER_SEC * 0xffffLL); 130 if (pre_div > MISC_CLK_DIV_MASK) { 131 printf("%s%d: unable to get period pre_div\n", __func__, channeln); 132 return -EINVAL; 133 } 134 135 cnt = div64_u64(fin_freq * (u64)period, NSEC_PER_SEC * (pre_div + 1)); 136 if (cnt > 0xffff) { 137 printf("%s%d: unable to get period cnt\n", __func__, channeln); 138 return -EINVAL; 139 } 140 141 debug("%s%d: period=%u pre_div=%u cnt=%u\n", __func__, channeln, period, pre_div, cnt); 142 143 if (duty == period) { 144 channel->pre_div = pre_div; 145 channel->hi = cnt; 146 channel->lo = 0; 147 } else if (duty == 0) { 148 channel->pre_div = pre_div; 149 channel->hi = 0; 150 channel->lo = cnt; 151 } else { 152 /* Then check is we can have the duty with the same pre_div */ 153 duty_cnt = div64_u64(fin_freq * (u64)duty, NSEC_PER_SEC * (pre_div + 1)); 154 if (duty_cnt > 0xffff) { 155 printf("%s%d: unable to get duty cycle\n", __func__, channeln); 156 return -EINVAL; 157 } 158 159 debug("%s%d: duty=%u pre_div=%u duty_cnt=%u\n", 160 __func__, channeln, duty, pre_div, duty_cnt); 161 162 channel->pre_div = pre_div; 163 channel->hi = duty_cnt; 164 channel->lo = cnt - duty_cnt; 165 } 166 167 channel->period_ns = period_ns; 168 channel->duty_ns = duty_ns; 169 channel->configured = true; 170 171 if (channel->enabled) { 172 meson_pwm_set_enable(dev, channeln, false); 173 meson_pwm_set_enable(dev, channeln, true); 174 } 175 176 return 0; 177} 178 179static int meson_pwm_set_enable(struct udevice *dev, uint channeln, bool enable) 180{ 181 struct meson_pwm *priv = dev_get_priv(dev); 182 struct meson_pwm_channel *channel; 183 struct meson_pwm_channel_data *channel_data; 184 u32 value; 185 186 if (channeln >= MESON_NUM_PWMS) 187 return -ENODEV; 188 189 channel = &priv->channels[channeln]; 190 channel_data = &meson_pwm_per_channel_data[channeln]; 191 192 if (!channel->configured) 193 return -EINVAL; 194 195 if (enable) { 196 if (channel->enabled) 197 return 0; 198 199 value = readl(priv->base + REG_MISC_AB); 200 value &= ~(MISC_CLK_DIV_MASK << channel_data->clk_div_shift); 201 value |= channel->pre_div << channel_data->clk_div_shift; 202 value |= channel_data->clk_en_mask; 203 writel(value, priv->base + REG_MISC_AB); 204 205 value = FIELD_PREP(PWM_HIGH_MASK, channel->hi) | 206 FIELD_PREP(PWM_LOW_MASK, channel->lo); 207 writel(value, priv->base + channel_data->reg_offset); 208 209 value = readl(priv->base + REG_MISC_AB); 210 value |= channel_data->pwm_en_mask; 211 writel(value, priv->base + REG_MISC_AB); 212 213 debug("%s%d: enabled\n", __func__, channeln); 214 channel->enabled = true; 215 } else { 216 if (!channel->enabled) 217 return 0; 218 219 value = readl(priv->base + REG_MISC_AB); 220 value &= channel_data->pwm_en_mask; 221 writel(value, priv->base + REG_MISC_AB); 222 223 debug("%s%d: disabled\n", __func__, channeln); 224 channel->enabled = false; 225 } 226 227 return 0; 228} 229 230static int meson_pwm_set_invert(struct udevice *dev, uint channeln, bool polarity) 231{ 232 struct meson_pwm *priv = dev_get_priv(dev); 233 struct meson_pwm_channel *channel; 234 235 if (channeln >= MESON_NUM_PWMS) 236 return -ENODEV; 237 238 debug("%s%d: set invert %s\n", __func__, channeln, polarity ? "true" : "false"); 239 240 channel = &priv->channels[channeln]; 241 242 channel->polarity = polarity; 243 244 if (!channel->configured) 245 return 0; 246 247 return meson_pwm_set_config(dev, channeln, channel->period_ns, channel->duty_ns); 248} 249 250static int meson_pwm_of_to_plat(struct udevice *dev) 251{ 252 struct meson_pwm *priv = dev_get_priv(dev); 253 254 priv->base = dev_read_addr_ptr(dev); 255 256 return 0; 257} 258 259static int meson_pwm_probe(struct udevice *dev) 260{ 261 struct meson_pwm *priv = dev_get_priv(dev); 262 struct meson_pwm_data *data; 263 unsigned int i, p; 264 char name[255]; 265 int err; 266 u32 reg; 267 268 data = (struct meson_pwm_data *)dev_get_driver_data(dev); 269 if (!data) 270 return -EINVAL; 271 272 for (i = 0; i < MESON_NUM_PWMS; i++) { 273 struct meson_pwm_channel *channel = &priv->channels[i]; 274 struct meson_pwm_channel_data *channel_data = &meson_pwm_per_channel_data[i]; 275 276 snprintf(name, sizeof(name), "clkin%u", i); 277 278 err = clk_get_by_name(dev, name, &channel->clk); 279 /* If clock is not specified, use the already set clock */ 280 if (err == -ENODATA) { 281 struct udevice *cdev; 282 struct uclass *uc; 283 284 /* Get parent from mux */ 285 p = (readl(priv->base + REG_MISC_AB) >> channel_data->clk_sel_shift) & 286 MISC_CLK_SEL_MASK; 287 288 if (p >= data->num_parents) { 289 printf("%s%d: hw parent is invalid\n", __func__, i); 290 return -EINVAL; 291 } 292 293 if (data->parent_ids[p] == -1) { 294 /* Search for xtal clk */ 295 const char *str; 296 297 err = uclass_get(UCLASS_CLK, &uc); 298 if (err) 299 return err; 300 301 uclass_foreach_dev(cdev, uc) { 302 if (strcmp(cdev->driver->name, "fixed_rate_clock")) 303 continue; 304 305 str = ofnode_read_string(dev_ofnode(cdev), 306 "clock-output-names"); 307 if (!str) 308 continue; 309 310 if (!strcmp(str, "xtal")) { 311 err = uclass_get_device_by_ofnode(UCLASS_CLK, 312 dev_ofnode(cdev), 313 &cdev); 314 if (err) { 315 printf("%s%d: Failed to get xtal clk\n", __func__, i); 316 return err; 317 } 318 319 break; 320 } 321 } 322 323 if (!cdev) { 324 printf("%s%d: Failed to find xtal clk device\n", __func__, i); 325 return -EINVAL; 326 } 327 328 channel->clk.dev = cdev; 329 channel->clk.id = 0; 330 channel->clk.data = 0; 331 } else { 332 /* Look for parent clock */ 333 err = uclass_get(UCLASS_CLK, &uc); 334 if (err) 335 return err; 336 337 uclass_foreach_dev(cdev, uc) { 338 if (strstr(cdev->driver->name, "meson_clk")) 339 break; 340 } 341 342 if (!cdev) { 343 printf("%s%d: Failed to find clk device\n", __func__, i); 344 return -EINVAL; 345 } 346 347 err = uclass_get_device_by_ofnode(UCLASS_CLK, 348 dev_ofnode(cdev), 349 &cdev); 350 if (err) { 351 printf("%s%d: Failed to get clk controller\n", __func__, i); 352 return err; 353 } 354 355 channel->clk.dev = cdev; 356 channel->clk.id = data->parent_ids[p]; 357 channel->clk.data = 0; 358 } 359 360 /* We have our source clock, do not alter HW clock mux */ 361 continue; 362 } else 363 return err; 364 365 /* Get id in list */ 366 for (p = 0 ; p < data->num_parents ; ++p) { 367 if (!strcmp(channel->clk.dev->driver->name, "fixed_rate_clock")) { 368 if (data->parent_ids[p] == -1) 369 break; 370 } else { 371 if (data->parent_ids[p] == channel->clk.id) 372 break; 373 } 374 } 375 376 /* Invalid clock ID */ 377 if (p == data->num_parents) { 378 printf("%s%d: source clock is invalid\n", __func__, i); 379 return -EINVAL; 380 } 381 382 /* switch parent in mux */ 383 reg = readl(priv->base + REG_MISC_AB); 384 385 debug("%s%d: switching parent %d to %d\n", __func__, i, 386 (reg >> channel_data->clk_sel_shift) & MISC_CLK_SEL_MASK, p); 387 388 reg &= MISC_CLK_SEL_MASK << channel_data->clk_sel_shift; 389 reg |= (p & MISC_CLK_SEL_MASK) << channel_data->clk_sel_shift; 390 writel(reg, priv->base + REG_MISC_AB); 391 } 392 393 return 0; 394} 395 396static const struct pwm_ops meson_pwm_ops = { 397 .set_config = meson_pwm_set_config, 398 .set_enable = meson_pwm_set_enable, 399 .set_invert = meson_pwm_set_invert, 400}; 401 402#define XTAL -1 403 404/* Local clock ids aliases to avoid define conflicts */ 405#define GXBB_CLKID_HDMI_PLL 2 406#define GXBB_CLKID_FCLK_DIV3 5 407#define GXBB_CLKID_FCLK_DIV4 6 408#define GXBB_CLKID_CLK81 12 409 410static const long pwm_gxbb_parent_ids[] = { 411 XTAL, GXBB_CLKID_HDMI_PLL, GXBB_CLKID_FCLK_DIV4, GXBB_CLKID_FCLK_DIV3 412}; 413 414static const struct meson_pwm_data pwm_gxbb_data = { 415 .parent_ids = pwm_gxbb_parent_ids, 416 .num_parents = ARRAY_SIZE(pwm_gxbb_parent_ids), 417}; 418 419/* 420 * Only the 2 first inputs of the GXBB AO PWMs are valid 421 * The last 2 are grounded 422 */ 423static const long pwm_gxbb_ao_parent_ids[] = { 424 XTAL, GXBB_CLKID_CLK81 425}; 426 427static const struct meson_pwm_data pwm_gxbb_ao_data = { 428 .parent_ids = pwm_gxbb_ao_parent_ids, 429 .num_parents = ARRAY_SIZE(pwm_gxbb_ao_parent_ids), 430}; 431 432/* Local clock ids aliases to avoid define conflicts */ 433#define AXG_CLKID_FCLK_DIV3 3 434#define AXG_CLKID_FCLK_DIV4 4 435#define AXG_CLKID_FCLK_DIV5 5 436#define AXG_CLKID_CLK81 10 437 438static const long pwm_axg_ee_parent_ids[] = { 439 XTAL, AXG_CLKID_FCLK_DIV5, AXG_CLKID_FCLK_DIV4, AXG_CLKID_FCLK_DIV3 440}; 441 442static const struct meson_pwm_data pwm_axg_ee_data = { 443 .parent_ids = pwm_axg_ee_parent_ids, 444 .num_parents = ARRAY_SIZE(pwm_axg_ee_parent_ids), 445}; 446 447static const long pwm_axg_ao_parent_ids[] = { 448 AXG_CLKID_CLK81, XTAL, AXG_CLKID_FCLK_DIV4, AXG_CLKID_FCLK_DIV5 449}; 450 451static const struct meson_pwm_data pwm_axg_ao_data = { 452 .parent_ids = pwm_axg_ao_parent_ids, 453 .num_parents = ARRAY_SIZE(pwm_axg_ao_parent_ids), 454}; 455 456/* Local clock ids aliases to avoid define conflicts */ 457#define G12A_CLKID_FCLK_DIV3 3 458#define G12A_CLKID_FCLK_DIV4 4 459#define G12A_CLKID_FCLK_DIV5 5 460#define G12A_CLKID_CLK81 10 461#define G12A_CLKID_HDMI_PLL 128 462 463static const long pwm_g12a_ao_ab_parent_ids[] = { 464 XTAL, G12A_CLKID_CLK81, G12A_CLKID_FCLK_DIV4, G12A_CLKID_FCLK_DIV5 465}; 466 467static const struct meson_pwm_data pwm_g12a_ao_ab_data = { 468 .parent_ids = pwm_g12a_ao_ab_parent_ids, 469 .num_parents = ARRAY_SIZE(pwm_g12a_ao_ab_parent_ids), 470}; 471 472static const long pwm_g12a_ao_cd_parent_ids[] = { 473 XTAL, G12A_CLKID_CLK81, 474}; 475 476static const struct meson_pwm_data pwm_g12a_ao_cd_data = { 477 .parent_ids = pwm_g12a_ao_cd_parent_ids, 478 .num_parents = ARRAY_SIZE(pwm_g12a_ao_cd_parent_ids), 479}; 480 481static const long pwm_g12a_ee_parent_ids[] = { 482 XTAL, G12A_CLKID_HDMI_PLL, G12A_CLKID_FCLK_DIV4, G12A_CLKID_FCLK_DIV3 483}; 484 485static const struct meson_pwm_data pwm_g12a_ee_data = { 486 .parent_ids = pwm_g12a_ee_parent_ids, 487 .num_parents = ARRAY_SIZE(pwm_g12a_ee_parent_ids), 488}; 489 490static const struct udevice_id meson_pwm_ids[] = { 491 { 492 .compatible = "amlogic,meson-gxbb-pwm", 493 .data = (ulong)&pwm_gxbb_data 494 }, 495 { 496 .compatible = "amlogic,meson-gxbb-ao-pwm", 497 .data = (ulong)&pwm_gxbb_ao_data 498 }, 499 { 500 .compatible = "amlogic,meson-axg-ee-pwm", 501 .data = (ulong)&pwm_axg_ee_data 502 }, 503 { 504 .compatible = "amlogic,meson-axg-ao-pwm", 505 .data = (ulong)&pwm_axg_ao_data 506 }, 507 { 508 .compatible = "amlogic,meson-g12a-ee-pwm", 509 .data = (ulong)&pwm_g12a_ee_data 510 }, 511 { 512 .compatible = "amlogic,meson-g12a-ao-pwm-ab", 513 .data = (ulong)&pwm_g12a_ao_ab_data 514 }, 515 { 516 .compatible = "amlogic,meson-g12a-ao-pwm-cd", 517 .data = (ulong)&pwm_g12a_ao_cd_data 518 }, 519}; 520 521U_BOOT_DRIVER(meson_pwm) = { 522 .name = "meson_pwm", 523 .id = UCLASS_PWM, 524 .of_match = meson_pwm_ids, 525 .ops = &meson_pwm_ops, 526 .of_to_plat = meson_pwm_of_to_plat, 527 .probe = meson_pwm_probe, 528 .priv_auto = sizeof(struct meson_pwm), 529}; 530