1 /* 2 * Copyright (c) 2016 Google, Inc 3 * Written by Simon Glass <sjg@chromium.org> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <clk.h> 10 #include <div64.h> 11 #include <dm.h> 12 #include <dm/pinctrl.h> 13 #include <pwm.h> 14 #include <regmap.h> 15 #include <syscon.h> 16 #include <asm/io.h> 17 #include <asm/arch/pwm.h> 18 #include <power/regulator.h> 19 20 DECLARE_GLOBAL_DATA_PTR; 21 22 /* 23 * regs for pwm v4 24 */ 25 #define HIWORD_UPDATE(v, l, h) (((v) << (l)) | (GENMASK(h, l) << 16)) 26 27 /* VERSION_ID */ 28 #define VERSION_ID 0x0 29 #define CHANNEL_NUM_SUPPORT_SHIFT 0 30 #define CHANNEL_NUM_SUPPORT_MASK (0xf << CHANNEL_NUM_SUPPORT_SHIFT) 31 #define CHANNLE_INDEX_SHIFT 4 32 #define CHANNLE_INDEX_MASK (0xf << CHANNLE_INDEX_SHIFT) 33 /* ENABLE */ 34 #define ENABLE 0x4 35 #define PWM_ENABLE_V4 (0x3 << 0) 36 #define PWM_CLK_EN(v) HIWORD_UPDATE(v, 0, 0) 37 #define PWM_EN(v) HIWORD_UPDATE(v, 1, 1) 38 #define PWM_CTRL_UPDATE_EN(v) HIWORD_UPDATE(v, 2, 2) 39 #define PWM_GLOBAL_JOIN_EN(v) HIWORD_UPDATE(v, 4, 4) 40 /* CLK_CTRL */ 41 #define CLK_CTRL 0x8 42 #define CLK_PRESCALE(v) HIWORD_UPDATE(v, 0, 2) 43 #define CLK_SCALE(v) HIWORD_UPDATE(v, 4, 12) 44 #define CLK_SRC_SEL(v) HIWORD_UPDATE(v, 13, 14) 45 #define CLK_GLOBAL_SEL(v) HIWORD_UPDATE(v, 15, 15) 46 /* CTRL */ 47 #define CTRL_V4 0xc 48 #define PWM_MODE(v) HIWORD_UPDATE(v, 0, 1) 49 #define ONESHOT_MODE 0 50 #define CONTINUOUS_MODE 1 51 #define CAPTURE_MODE 2 52 #define PWM_POLARITY(v) HIWORD_UPDATE(v, 2, 3) 53 #define DUTY_NEGATIVE (0 << 0) 54 #define DUTY_POSITIVE (1 << 0) 55 #define INACTIVE_NEGATIVE (0 << 1) 56 #define INACTIVE_POSITIVE (1 << 1) 57 #define PWM_ALIGNED_INVALID(v) HIWORD_UPDATE(v, 5, 5) 58 #define PWM_IN_SEL(v) HIWORD_UPDATE(v, 6, 8) 59 /* PERIOD */ 60 #define PERIOD 0x10 61 /* DUTY */ 62 #define DUTY 0x14 63 64 struct rk_pwm_priv { 65 fdt_addr_t base; 66 ulong freq; 67 u32 conf_polarity; 68 bool vop_pwm_en; /* indicate voppwm mirror register state */ 69 const struct rockchip_pwm_data *data; 70 }; 71 72 struct rockchip_pwm_funcs { 73 int (*set_invert)(struct udevice *dev, uint channel, bool polarity); 74 int (*set_config)(struct udevice *dev, uint channel, 75 uint period_ns, uint duty_ns); 76 int (*set_enable)(struct udevice *dev, uint channel, bool enable); 77 }; 78 79 struct rockchip_pwm_data { 80 struct rockchip_pwm_regs regs; 81 struct rockchip_pwm_funcs funcs; 82 unsigned int prescaler; 83 bool supports_polarity; 84 bool supports_lock; 85 bool vop_pwm; 86 u8 main_version; 87 u32 enable_conf; 88 u32 enable_conf_mask; 89 }; 90 91 static int rk_pwm_set_invert_v4(struct udevice *dev, uint channel, bool polarity) 92 { 93 struct rk_pwm_priv *priv = dev_get_priv(dev); 94 95 debug("%s: polarity=%u\n", __func__, polarity); 96 if (polarity) 97 priv->conf_polarity = PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE; 98 else 99 priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE; 100 101 return 0; 102 } 103 104 static int rk_pwm_set_invert_v1(struct udevice *dev, uint channel, bool polarity) 105 { 106 struct rk_pwm_priv *priv = dev_get_priv(dev); 107 108 debug("%s: polarity=%u\n", __func__, polarity); 109 if (polarity) 110 priv->conf_polarity = PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE; 111 else 112 priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE; 113 114 return 0; 115 } 116 117 static int rk_pwm_set_invert(struct udevice *dev, uint channel, bool polarity) 118 { 119 struct rk_pwm_priv *priv = dev_get_priv(dev); 120 121 if (!priv->data->supports_polarity) { 122 debug("%s: Do not support polarity\n", __func__); 123 return 0; 124 } 125 126 return priv->data->funcs.set_invert(dev, channel, polarity); 127 } 128 129 static int rk_pwm_set_config_v4(struct udevice *dev, uint channel, 130 uint period_ns, uint duty_ns) 131 { 132 struct rk_pwm_priv *priv = dev_get_priv(dev); 133 unsigned long period, duty; 134 135 period = lldiv((uint64_t)(priv->freq / 1000) * period_ns, 136 priv->data->prescaler * 1000000); 137 duty = lldiv((uint64_t)(priv->freq / 1000) * duty_ns, 138 priv->data->prescaler * 1000000); 139 140 writel(period, priv->base + PERIOD); 141 writel(duty, priv->base + DUTY); 142 143 if (priv->data->supports_polarity) 144 writel(PWM_POLARITY(priv->conf_polarity), priv->base + CTRL_V4); 145 146 writel(PWM_MODE(CONTINUOUS_MODE) | PWM_ALIGNED_INVALID(false), 147 priv->base + CTRL_V4); 148 149 writel(PWM_CTRL_UPDATE_EN(true), priv->base + ENABLE); 150 151 debug("%s: period=%lu, duty=%lu\n", __func__, period, duty); 152 153 return 0; 154 } 155 156 static int rk_pwm_set_config_v1(struct udevice *dev, uint channel, 157 uint period_ns, uint duty_ns) 158 { 159 struct rk_pwm_priv *priv = dev_get_priv(dev); 160 const struct rockchip_pwm_regs *regs = &priv->data->regs; 161 unsigned long period, duty; 162 u32 ctrl; 163 164 debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns); 165 166 ctrl = readl(priv->base + regs->ctrl); 167 if (priv->data->vop_pwm) { 168 if (priv->vop_pwm_en) 169 ctrl |= RK_PWM_ENABLE; 170 else 171 ctrl &= ~RK_PWM_ENABLE; 172 } 173 174 /* 175 * Lock the period and duty of previous configuration, then 176 * change the duty and period, that would not be effective. 177 */ 178 if (priv->data->supports_lock) { 179 ctrl |= PWM_LOCK; 180 writel(ctrl, priv->base + regs->ctrl); 181 } 182 183 period = lldiv((uint64_t)(priv->freq / 1000) * period_ns, 184 priv->data->prescaler * 1000000); 185 duty = lldiv((uint64_t)(priv->freq / 1000) * duty_ns, 186 priv->data->prescaler * 1000000); 187 188 writel(period, priv->base + regs->period); 189 writel(duty, priv->base + regs->duty); 190 191 if (priv->data->supports_polarity) { 192 ctrl &= ~(PWM_DUTY_MASK | PWM_INACTIVE_MASK); 193 ctrl |= priv->conf_polarity; 194 } 195 196 /* 197 * Unlock and set polarity at the same time, 198 * the configuration of duty, period and polarity 199 * would be effective together at next period. 200 */ 201 if (priv->data->supports_lock) 202 ctrl &= ~PWM_LOCK; 203 writel(ctrl, priv->base + regs->ctrl); 204 205 debug("%s: period=%lu, duty=%lu\n", __func__, period, duty); 206 207 return 0; 208 } 209 210 static int rk_pwm_set_config(struct udevice *dev, uint channel, 211 uint period_ns, uint duty_ns) 212 { 213 struct rk_pwm_priv *priv = dev_get_priv(dev); 214 215 return priv->data->funcs.set_config(dev, channel, period_ns, duty_ns); 216 } 217 218 static int rk_pwm_set_enable_v4(struct udevice *dev, uint channel, bool enable) 219 { 220 struct rk_pwm_priv *priv = dev_get_priv(dev); 221 222 debug("%s: Enable '%s'\n", __func__, dev->name); 223 224 writel(PWM_EN(enable) | PWM_CLK_EN(enable), priv->base + ENABLE); 225 226 if (enable) 227 pinctrl_select_state(dev, "active"); 228 229 return 0; 230 } 231 232 static int rk_pwm_set_enable_v1(struct udevice *dev, uint channel, bool enable) 233 { 234 struct rk_pwm_priv *priv = dev_get_priv(dev); 235 const struct rockchip_pwm_regs *regs = &priv->data->regs; 236 u32 ctrl; 237 238 debug("%s: Enable '%s'\n", __func__, dev->name); 239 240 ctrl = readl(priv->base + regs->ctrl); 241 ctrl &= ~priv->data->enable_conf_mask; 242 243 if (enable) 244 ctrl |= priv->data->enable_conf; 245 else 246 ctrl &= ~priv->data->enable_conf; 247 248 writel(ctrl, priv->base + regs->ctrl); 249 if (priv->data->vop_pwm) 250 priv->vop_pwm_en = enable; 251 252 if (enable) 253 pinctrl_select_state(dev, "active"); 254 255 return 0; 256 } 257 258 static int rk_pwm_set_enable(struct udevice *dev, uint channel, bool enable) 259 { 260 struct rk_pwm_priv *priv = dev_get_priv(dev); 261 262 return priv->data->funcs.set_enable(dev, channel, enable); 263 } 264 265 static int rk_pwm_ofdata_to_platdata(struct udevice *dev) 266 { 267 struct rk_pwm_priv *priv = dev_get_priv(dev); 268 269 priv->base = dev_read_addr(dev); 270 271 return 0; 272 } 273 274 static int rk_pwm_probe(struct udevice *dev) 275 { 276 struct rk_pwm_priv *priv = dev_get_priv(dev); 277 struct clk clk; 278 int ret = 0; 279 280 ret = clk_get_by_index(dev, 0, &clk); 281 if (ret < 0) { 282 debug("%s get clock fail!\n", __func__); 283 return -EINVAL; 284 } 285 286 ret = clk_get_rate(&clk); 287 if (ret < 0) { 288 debug("%s pwm get clock rate fail!\n", __func__); 289 return -EINVAL; 290 } 291 priv->freq = ret; 292 priv->data = (struct rockchip_pwm_data *)dev_get_driver_data(dev); 293 294 if (priv->data->supports_polarity) 295 priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE; 296 297 return 0; 298 } 299 300 static const struct pwm_ops rk_pwm_ops = { 301 .set_invert = rk_pwm_set_invert, 302 .set_config = rk_pwm_set_config, 303 .set_enable = rk_pwm_set_enable, 304 }; 305 306 static const struct rockchip_pwm_data pwm_data_v1 = { 307 .main_version = 0x01, 308 .regs = { 309 .version = 0x5c, 310 .duty = 0x04, 311 .period = 0x08, 312 .ctrl = 0x0c, 313 }, 314 .prescaler = 2, 315 .supports_polarity = false, 316 .supports_lock = false, 317 .vop_pwm = false, 318 .enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN, 319 .enable_conf_mask = BIT(1) | BIT(3), 320 .funcs = { 321 .set_invert = rk_pwm_set_invert_v1, 322 .set_config = rk_pwm_set_config_v1, 323 .set_enable = rk_pwm_set_enable_v1, 324 }, 325 }; 326 327 static const struct rockchip_pwm_data pwm_data_v2 = { 328 .main_version = 0x02, 329 .regs = { 330 .version = 0x5c, 331 .duty = 0x08, 332 .period = 0x04, 333 .ctrl = 0x0c, 334 }, 335 .prescaler = 1, 336 .supports_polarity = true, 337 .supports_lock = false, 338 .vop_pwm = false, 339 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE | 340 PWM_CONTINUOUS, 341 .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8), 342 .funcs = { 343 .set_invert = rk_pwm_set_invert_v1, 344 .set_config = rk_pwm_set_config_v1, 345 .set_enable = rk_pwm_set_enable_v1, 346 }, 347 }; 348 349 static const struct rockchip_pwm_data pwm_data_vop = { 350 .main_version = 0x02, 351 .regs = { 352 .version = 0x5c, 353 .duty = 0x08, 354 .period = 0x04, 355 .ctrl = 0x00, 356 }, 357 .prescaler = 1, 358 .supports_polarity = true, 359 .supports_lock = false, 360 .vop_pwm = true, 361 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE | 362 PWM_CONTINUOUS, 363 .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8), 364 .funcs = { 365 .set_invert = rk_pwm_set_invert_v1, 366 .set_config = rk_pwm_set_config_v1, 367 .set_enable = rk_pwm_set_enable_v1, 368 }, 369 }; 370 371 static const struct rockchip_pwm_data pwm_data_v3 = { 372 .main_version = 0x03, 373 .regs = { 374 .version = 0x5c, 375 .duty = 0x08, 376 .period = 0x04, 377 .ctrl = 0x0c, 378 }, 379 .prescaler = 1, 380 .supports_polarity = true, 381 .supports_lock = true, 382 .vop_pwm = false, 383 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE | 384 PWM_CONTINUOUS, 385 .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8), 386 .funcs = { 387 .set_invert = rk_pwm_set_invert_v1, 388 .set_config = rk_pwm_set_config_v1, 389 .set_enable = rk_pwm_set_enable_v1, 390 }, 391 }; 392 393 static const struct rockchip_pwm_data pwm_data_v4 = { 394 .main_version = 0x04, 395 .regs = { 396 .version = 0x0, 397 .enable = 0x4, 398 .ctrl = 0xc, 399 .period = 0x10, 400 .duty = 0x14, 401 }, 402 .prescaler = 1, 403 .supports_polarity = true, 404 .supports_lock = true, 405 .vop_pwm = false, 406 .enable_conf = PWM_ENABLE_V4, 407 .funcs = { 408 .set_invert = rk_pwm_set_invert_v4, 409 .set_config = rk_pwm_set_config_v4, 410 .set_enable = rk_pwm_set_enable_v4, 411 }, 412 }; 413 414 static const struct udevice_id rk_pwm_ids[] = { 415 { .compatible = "rockchip,rk2928-pwm", .data = (ulong)&pwm_data_v1}, 416 { .compatible = "rockchip,rk3288-pwm", .data = (ulong)&pwm_data_v2}, 417 { .compatible = "rockchip,rk3328-pwm", .data = (ulong)&pwm_data_v3}, 418 { .compatible = "rockchip,vop-pwm", .data = (ulong)&pwm_data_vop}, 419 { .compatible = "rockchip,rk3399-pwm", .data = (ulong)&pwm_data_v2}, 420 { .compatible = "rockchip,rk3576-pwm", .data = (ulong)&pwm_data_v4}, 421 { } 422 }; 423 424 U_BOOT_DRIVER(rk_pwm) = { 425 .name = "rk_pwm", 426 .id = UCLASS_PWM, 427 .of_match = rk_pwm_ids, 428 .ops = &rk_pwm_ops, 429 .ofdata_to_platdata = rk_pwm_ofdata_to_platdata, 430 .probe = rk_pwm_probe, 431 .priv_auto_alloc_size = sizeof(struct rk_pwm_priv), 432 }; 433