| .. | .. |
|---|
| 19 | 19 | #include <linux/of_irq.h> |
|---|
| 20 | 20 | #include <linux/of_platform.h> |
|---|
| 21 | 21 | #include <linux/platform_device.h> |
|---|
| 22 | +#include <linux/workqueue.h> |
|---|
| 23 | +#include <linux/notifier.h> |
|---|
| 22 | 24 | #include <linux/slab.h> |
|---|
| 23 | 25 | #include <linux/acpi.h> |
|---|
| 24 | 26 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 27 | 29 | |
|---|
| 28 | 30 | #include <asm/byteorder.h> |
|---|
| 29 | 31 | |
|---|
| 30 | | -#include "8250.h" |
|---|
| 32 | +#ifdef MODULE |
|---|
| 33 | +#include "8250_dwlib.c" |
|---|
| 34 | +#else |
|---|
| 35 | +#include "8250_dwlib.h" |
|---|
| 36 | +#endif |
|---|
| 31 | 37 | |
|---|
| 32 | 38 | /* Offsets for the DesignWare specific registers */ |
|---|
| 33 | 39 | #define DW_UART_USR 0x1f /* UART Status Register */ |
|---|
| 34 | | -#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */ |
|---|
| 35 | 40 | #define DW_UART_RFL 0x21 /* UART Receive Fifo Level Register */ |
|---|
| 36 | | -#define DW_UART_CPR 0xf4 /* Component Parameter Register */ |
|---|
| 37 | | -#define DW_UART_UCV 0xf8 /* UART Component Version */ |
|---|
| 38 | | - |
|---|
| 39 | | -/* Component Parameter Register bits */ |
|---|
| 40 | | -#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0) |
|---|
| 41 | | -#define DW_UART_CPR_AFCE_MODE (1 << 4) |
|---|
| 42 | | -#define DW_UART_CPR_THRE_MODE (1 << 5) |
|---|
| 43 | | -#define DW_UART_CPR_SIR_MODE (1 << 6) |
|---|
| 44 | | -#define DW_UART_CPR_SIR_LP_MODE (1 << 7) |
|---|
| 45 | | -#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8) |
|---|
| 46 | | -#define DW_UART_CPR_FIFO_ACCESS (1 << 9) |
|---|
| 47 | | -#define DW_UART_CPR_FIFO_STAT (1 << 10) |
|---|
| 48 | | -#define DW_UART_CPR_SHADOW (1 << 11) |
|---|
| 49 | | -#define DW_UART_CPR_ENCODED_PARMS (1 << 12) |
|---|
| 50 | | -#define DW_UART_CPR_DMA_EXTRA (1 << 13) |
|---|
| 51 | | -#define DW_UART_CPR_FIFO_MODE (0xff << 16) |
|---|
| 52 | | -/* Helper for fifo size calculation */ |
|---|
| 53 | | -#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16) |
|---|
| 54 | 41 | |
|---|
| 55 | 42 | /* DesignWare specific register fields */ |
|---|
| 56 | 43 | #define DW_UART_MCR_SIRE BIT(6) |
|---|
| 57 | 44 | |
|---|
| 58 | 45 | struct dw8250_data { |
|---|
| 46 | + struct dw8250_port_data data; |
|---|
| 47 | + |
|---|
| 59 | 48 | u8 usr_reg; |
|---|
| 60 | | - u8 dlf_size; |
|---|
| 61 | | - int line; |
|---|
| 62 | 49 | int msr_mask_on; |
|---|
| 63 | 50 | int msr_mask_off; |
|---|
| 64 | 51 | struct clk *clk; |
|---|
| 65 | 52 | struct clk *pclk; |
|---|
| 53 | + struct notifier_block clk_notifier; |
|---|
| 54 | + struct work_struct clk_work; |
|---|
| 66 | 55 | struct reset_control *rst; |
|---|
| 67 | | - struct uart_8250_dma dma; |
|---|
| 56 | + |
|---|
| 68 | 57 | #ifdef CONFIG_ARCH_ROCKCHIP |
|---|
| 69 | 58 | int irq; |
|---|
| 70 | 59 | int irq_wake; |
|---|
| .. | .. |
|---|
| 74 | 63 | unsigned int uart_16550_compatible:1; |
|---|
| 75 | 64 | }; |
|---|
| 76 | 65 | |
|---|
| 77 | | -static inline u32 dw8250_readl_ext(struct uart_port *p, int offset) |
|---|
| 66 | +static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data) |
|---|
| 78 | 67 | { |
|---|
| 79 | | - if (p->iotype == UPIO_MEM32BE) |
|---|
| 80 | | - return ioread32be(p->membase + offset); |
|---|
| 81 | | - return readl(p->membase + offset); |
|---|
| 68 | + return container_of(data, struct dw8250_data, data); |
|---|
| 82 | 69 | } |
|---|
| 83 | 70 | |
|---|
| 84 | | -static inline void dw8250_writel_ext(struct uart_port *p, int offset, u32 reg) |
|---|
| 71 | +static inline struct dw8250_data *clk_to_dw8250_data(struct notifier_block *nb) |
|---|
| 85 | 72 | { |
|---|
| 86 | | - if (p->iotype == UPIO_MEM32BE) |
|---|
| 87 | | - iowrite32be(reg, p->membase + offset); |
|---|
| 88 | | - else |
|---|
| 89 | | - writel(reg, p->membase + offset); |
|---|
| 73 | + return container_of(nb, struct dw8250_data, clk_notifier); |
|---|
| 74 | +} |
|---|
| 75 | + |
|---|
| 76 | +static inline struct dw8250_data *work_to_dw8250_data(struct work_struct *work) |
|---|
| 77 | +{ |
|---|
| 78 | + return container_of(work, struct dw8250_data, clk_work); |
|---|
| 90 | 79 | } |
|---|
| 91 | 80 | |
|---|
| 92 | 81 | static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) |
|---|
| 93 | 82 | { |
|---|
| 94 | | - struct dw8250_data *d = p->private_data; |
|---|
| 83 | + struct dw8250_data *d = to_dw8250_data(p->private_data); |
|---|
| 95 | 84 | |
|---|
| 96 | 85 | /* Override any modem control signals if needed */ |
|---|
| 97 | 86 | if (offset == UART_MSR) { |
|---|
| .. | .. |
|---|
| 145 | 134 | /* Returns once the transmitter is empty or we run out of retries */ |
|---|
| 146 | 135 | static void dw8250_tx_wait_empty(struct uart_port *p) |
|---|
| 147 | 136 | { |
|---|
| 137 | + struct uart_8250_port *up = up_to_u8250p(p); |
|---|
| 148 | 138 | unsigned int tries = 20000; |
|---|
| 149 | 139 | unsigned int delay_threshold = tries - 1000; |
|---|
| 150 | 140 | unsigned int lsr; |
|---|
| 151 | 141 | |
|---|
| 152 | 142 | while (tries--) { |
|---|
| 153 | 143 | lsr = readb (p->membase + (UART_LSR << p->regshift)); |
|---|
| 144 | + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; |
|---|
| 145 | + |
|---|
| 154 | 146 | if (lsr & UART_LSR_TEMT) |
|---|
| 155 | 147 | break; |
|---|
| 156 | 148 | |
|---|
| .. | .. |
|---|
| 165 | 157 | |
|---|
| 166 | 158 | static void dw8250_serial_out38x(struct uart_port *p, int offset, int value) |
|---|
| 167 | 159 | { |
|---|
| 168 | | - struct dw8250_data *d = p->private_data; |
|---|
| 160 | + struct dw8250_data *d = to_dw8250_data(p->private_data); |
|---|
| 169 | 161 | |
|---|
| 170 | 162 | /* Allow the TX to drain before we reconfigure */ |
|---|
| 171 | 163 | if (offset == UART_LCR) |
|---|
| .. | .. |
|---|
| 180 | 172 | |
|---|
| 181 | 173 | static void dw8250_serial_out(struct uart_port *p, int offset, int value) |
|---|
| 182 | 174 | { |
|---|
| 183 | | - struct dw8250_data *d = p->private_data; |
|---|
| 175 | + struct dw8250_data *d = to_dw8250_data(p->private_data); |
|---|
| 184 | 176 | |
|---|
| 185 | 177 | writeb(value, p->membase + (offset << p->regshift)); |
|---|
| 186 | 178 | |
|---|
| .. | .. |
|---|
| 207 | 199 | |
|---|
| 208 | 200 | static void dw8250_serial_outq(struct uart_port *p, int offset, int value) |
|---|
| 209 | 201 | { |
|---|
| 210 | | - struct dw8250_data *d = p->private_data; |
|---|
| 202 | + struct dw8250_data *d = to_dw8250_data(p->private_data); |
|---|
| 211 | 203 | |
|---|
| 212 | 204 | value &= 0xff; |
|---|
| 213 | 205 | __raw_writeq(value, p->membase + (offset << p->regshift)); |
|---|
| .. | .. |
|---|
| 221 | 213 | |
|---|
| 222 | 214 | static void dw8250_serial_out32(struct uart_port *p, int offset, int value) |
|---|
| 223 | 215 | { |
|---|
| 224 | | - struct dw8250_data *d = p->private_data; |
|---|
| 216 | + struct dw8250_data *d = to_dw8250_data(p->private_data); |
|---|
| 225 | 217 | |
|---|
| 226 | 218 | writel(value, p->membase + (offset << p->regshift)); |
|---|
| 227 | 219 | |
|---|
| .. | .. |
|---|
| 238 | 230 | |
|---|
| 239 | 231 | static void dw8250_serial_out32be(struct uart_port *p, int offset, int value) |
|---|
| 240 | 232 | { |
|---|
| 241 | | - struct dw8250_data *d = p->private_data; |
|---|
| 233 | + struct dw8250_data *d = to_dw8250_data(p->private_data); |
|---|
| 242 | 234 | |
|---|
| 243 | 235 | iowrite32be(value, p->membase + (offset << p->regshift)); |
|---|
| 244 | 236 | |
|---|
| .. | .. |
|---|
| 256 | 248 | |
|---|
| 257 | 249 | static int dw8250_handle_irq(struct uart_port *p) |
|---|
| 258 | 250 | { |
|---|
| 259 | | - struct dw8250_data *d = p->private_data; |
|---|
| 251 | + struct dw8250_data *d = to_dw8250_data(p->private_data); |
|---|
| 260 | 252 | unsigned int iir = p->serial_in(p, UART_IIR); |
|---|
| 261 | 253 | unsigned int status, usr, rfl; |
|---|
| 262 | 254 | unsigned long flags; |
|---|
| .. | .. |
|---|
| 292 | 284 | return 0; |
|---|
| 293 | 285 | } |
|---|
| 294 | 286 | |
|---|
| 287 | +static void dw8250_clk_work_cb(struct work_struct *work) |
|---|
| 288 | +{ |
|---|
| 289 | + struct dw8250_data *d = work_to_dw8250_data(work); |
|---|
| 290 | + struct uart_8250_port *up; |
|---|
| 291 | + unsigned long rate; |
|---|
| 292 | + |
|---|
| 293 | + rate = clk_get_rate(d->clk); |
|---|
| 294 | + if (rate <= 0) |
|---|
| 295 | + return; |
|---|
| 296 | + |
|---|
| 297 | + up = serial8250_get_port(d->data.line); |
|---|
| 298 | + |
|---|
| 299 | + serial8250_update_uartclk(&up->port, rate); |
|---|
| 300 | +} |
|---|
| 301 | + |
|---|
| 302 | +static int dw8250_clk_notifier_cb(struct notifier_block *nb, |
|---|
| 303 | + unsigned long event, void *data) |
|---|
| 304 | +{ |
|---|
| 305 | + struct dw8250_data *d = clk_to_dw8250_data(nb); |
|---|
| 306 | + |
|---|
| 307 | + /* |
|---|
| 308 | + * We have no choice but to defer the uartclk update due to two |
|---|
| 309 | + * deadlocks. First one is caused by a recursive mutex lock which |
|---|
| 310 | + * happens when clk_set_rate() is called from dw8250_set_termios(). |
|---|
| 311 | + * Second deadlock is more tricky and is caused by an inverted order of |
|---|
| 312 | + * the clk and tty-port mutexes lock. It happens if clock rate change |
|---|
| 313 | + * is requested asynchronously while set_termios() is executed between |
|---|
| 314 | + * tty-port mutex lock and clk_set_rate() function invocation and |
|---|
| 315 | + * vise-versa. Anyway if we didn't have the reference clock alteration |
|---|
| 316 | + * in the dw8250_set_termios() method we wouldn't have needed this |
|---|
| 317 | + * deferred event handling complication. |
|---|
| 318 | + */ |
|---|
| 319 | + if (event == POST_RATE_CHANGE) { |
|---|
| 320 | + queue_work(system_unbound_wq, &d->clk_work); |
|---|
| 321 | + return NOTIFY_OK; |
|---|
| 322 | + } |
|---|
| 323 | + |
|---|
| 324 | + return NOTIFY_DONE; |
|---|
| 325 | +} |
|---|
| 326 | + |
|---|
| 295 | 327 | static void |
|---|
| 296 | 328 | dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) |
|---|
| 297 | 329 | { |
|---|
| .. | .. |
|---|
| 307 | 339 | static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, |
|---|
| 308 | 340 | struct ktermios *old) |
|---|
| 309 | 341 | { |
|---|
| 310 | | - unsigned int baud = tty_termios_baud_rate(termios); |
|---|
| 311 | | - struct dw8250_data *d = p->private_data; |
|---|
| 342 | +#ifndef CONFIG_ARCH_ROCKCHIP |
|---|
| 343 | + unsigned long newrate = tty_termios_baud_rate(termios) * 16; |
|---|
| 344 | +#endif |
|---|
| 345 | + struct dw8250_data *d = to_dw8250_data(p->private_data); |
|---|
| 312 | 346 | long rate; |
|---|
| 313 | 347 | #ifdef CONFIG_ARCH_ROCKCHIP |
|---|
| 348 | + unsigned int baud = tty_termios_baud_rate(termios); |
|---|
| 314 | 349 | unsigned int rate_temp, diff; |
|---|
| 315 | 350 | #endif |
|---|
| 316 | 351 | int ret; |
|---|
| 317 | 352 | |
|---|
| 318 | | - if (IS_ERR(d->clk)) |
|---|
| 319 | | - goto out; |
|---|
| 320 | | - |
|---|
| 321 | 353 | clk_disable_unprepare(d->clk); |
|---|
| 322 | 354 | #ifdef CONFIG_ARCH_ROCKCHIP |
|---|
| 323 | | - if (baud <= 115200) |
|---|
| 324 | | - rate = 24000000; |
|---|
| 325 | | - else if (baud == 230400) |
|---|
| 326 | | - rate = baud * 16 * 2; |
|---|
| 327 | | - else if (baud == 1152000) |
|---|
| 328 | | - rate = baud * 16 * 2; |
|---|
| 329 | | - else |
|---|
| 330 | | - rate = baud * 16; |
|---|
| 355 | + if (d->clk) { |
|---|
| 356 | + if (baud <= 115200) |
|---|
| 357 | + rate = 24000000; |
|---|
| 358 | + else if (baud == 230400) |
|---|
| 359 | + rate = baud * 16 * 2; |
|---|
| 360 | + else if (baud == 1152000) |
|---|
| 361 | + rate = baud * 16 * 2; |
|---|
| 362 | + else |
|---|
| 363 | + rate = baud * 16; |
|---|
| 331 | 364 | |
|---|
| 332 | | - ret = clk_set_rate(d->clk, rate); |
|---|
| 333 | | - rate_temp = clk_get_rate(d->clk); |
|---|
| 334 | | - diff = rate * 20 / 1000; |
|---|
| 335 | | - /* |
|---|
| 336 | | - * If rate_temp is not equal to rate, is means fractional frequency |
|---|
| 337 | | - * division is failed. Then use Integer frequency division, and |
|---|
| 338 | | - * the buad rate error must be under -+2% |
|---|
| 339 | | - */ |
|---|
| 340 | | - if ((rate_temp < rate) && ((rate - rate_temp) > diff)) { |
|---|
| 341 | | - ret = clk_set_rate(d->clk, rate + diff); |
|---|
| 365 | + ret = clk_set_rate(d->clk, rate); |
|---|
| 342 | 366 | rate_temp = clk_get_rate(d->clk); |
|---|
| 343 | | - if ((rate_temp < rate) && ((rate - rate_temp) > diff)) |
|---|
| 344 | | - dev_info(p->dev, "set rate:%ld, but get rate:%d\n", |
|---|
| 345 | | - rate, rate_temp); |
|---|
| 346 | | - else if ((rate < rate_temp) && ((rate_temp - rate) > diff)) |
|---|
| 347 | | - dev_info(p->dev, "set rate:%ld, but get rate:%d\n", |
|---|
| 348 | | - rate, rate_temp); |
|---|
| 367 | + diff = rate * 20 / 1000; |
|---|
| 368 | + /* |
|---|
| 369 | + * If rate_temp is not equal to rate, is means fractional frequency |
|---|
| 370 | + * division is failed. Then use Integer frequency division, and |
|---|
| 371 | + * the baud rate error must be under -+2% |
|---|
| 372 | + */ |
|---|
| 373 | + if ((rate_temp < rate) && ((rate - rate_temp) > diff)) { |
|---|
| 374 | + ret = clk_set_rate(d->clk, rate + diff); |
|---|
| 375 | + rate_temp = clk_get_rate(d->clk); |
|---|
| 376 | + if ((rate_temp < rate) && ((rate - rate_temp) > diff)) |
|---|
| 377 | + dev_info(p->dev, "set rate:%ld, but get rate:%d\n", |
|---|
| 378 | + rate, rate_temp); |
|---|
| 379 | + else if ((rate < rate_temp) && ((rate_temp - rate) > diff)) |
|---|
| 380 | + dev_info(p->dev, "set rate:%ld, but get rate:%d\n", |
|---|
| 381 | + rate, rate_temp); |
|---|
| 382 | + } |
|---|
| 383 | + if (!ret) |
|---|
| 384 | + p->uartclk = rate; |
|---|
| 349 | 385 | } |
|---|
| 350 | 386 | #else |
|---|
| 351 | | - rate = clk_round_rate(d->clk, baud * 16); |
|---|
| 352 | | - if (rate < 0) |
|---|
| 353 | | - ret = rate; |
|---|
| 354 | | - else if (rate == 0) |
|---|
| 355 | | - ret = -ENOENT; |
|---|
| 356 | | - else |
|---|
| 357 | | - ret = clk_set_rate(d->clk, rate); |
|---|
| 387 | + rate = clk_round_rate(d->clk, newrate); |
|---|
| 388 | + if (rate > 0) { |
|---|
| 389 | + /* |
|---|
| 390 | + * Premilinary set the uartclk to the new clock rate so the |
|---|
| 391 | + * clock update event handler caused by the clk_set_rate() |
|---|
| 392 | + * calling wouldn't actually update the UART divisor since |
|---|
| 393 | + * we about to do this anyway. |
|---|
| 394 | + */ |
|---|
| 395 | + swap(p->uartclk, rate); |
|---|
| 396 | + ret = clk_set_rate(d->clk, newrate); |
|---|
| 397 | + if (ret) |
|---|
| 398 | + swap(p->uartclk, rate); |
|---|
| 399 | + } |
|---|
| 358 | 400 | #endif |
|---|
| 359 | 401 | clk_prepare_enable(d->clk); |
|---|
| 360 | 402 | |
|---|
| 361 | | - if (!ret) |
|---|
| 362 | | - p->uartclk = rate; |
|---|
| 363 | | - |
|---|
| 364 | | -out: |
|---|
| 365 | 403 | p->status &= ~UPSTAT_AUTOCTS; |
|---|
| 366 | 404 | if (termios->c_cflag & CRTSCTS) |
|---|
| 367 | 405 | p->status |= UPSTAT_AUTOCTS; |
|---|
| .. | .. |
|---|
| 403 | 441 | return param == chan->device->dev; |
|---|
| 404 | 442 | } |
|---|
| 405 | 443 | |
|---|
| 406 | | -/* |
|---|
| 407 | | - * divisor = div(I) + div(F) |
|---|
| 408 | | - * "I" means integer, "F" means fractional |
|---|
| 409 | | - * quot = div(I) = clk / (16 * baud) |
|---|
| 410 | | - * frac = div(F) * 2^dlf_size |
|---|
| 411 | | - * |
|---|
| 412 | | - * let rem = clk % (16 * baud) |
|---|
| 413 | | - * we have: div(F) * (16 * baud) = rem |
|---|
| 414 | | - * so frac = 2^dlf_size * rem / (16 * baud) = (rem << dlf_size) / (16 * baud) |
|---|
| 415 | | - */ |
|---|
| 416 | | -static unsigned int dw8250_get_divisor(struct uart_port *p, |
|---|
| 417 | | - unsigned int baud, |
|---|
| 418 | | - unsigned int *frac) |
|---|
| 419 | | -{ |
|---|
| 420 | | - unsigned int quot, rem, base_baud = baud * 16; |
|---|
| 421 | | - struct dw8250_data *d = p->private_data; |
|---|
| 422 | | - |
|---|
| 423 | | - quot = p->uartclk / base_baud; |
|---|
| 424 | | - rem = p->uartclk % base_baud; |
|---|
| 425 | | - *frac = DIV_ROUND_CLOSEST(rem << d->dlf_size, base_baud); |
|---|
| 426 | | - |
|---|
| 427 | | - return quot; |
|---|
| 428 | | -} |
|---|
| 429 | | - |
|---|
| 430 | | -static void dw8250_set_divisor(struct uart_port *p, unsigned int baud, |
|---|
| 431 | | - unsigned int quot, unsigned int quot_frac) |
|---|
| 432 | | -{ |
|---|
| 433 | | - dw8250_writel_ext(p, DW_UART_DLF, quot_frac); |
|---|
| 434 | | - serial8250_do_set_divisor(p, baud, quot, quot_frac); |
|---|
| 435 | | -} |
|---|
| 436 | | - |
|---|
| 437 | 444 | static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) |
|---|
| 438 | 445 | { |
|---|
| 439 | 446 | if (p->dev->of_node) { |
|---|
| .. | .. |
|---|
| 444 | 451 | id = of_alias_get_id(np, "serial"); |
|---|
| 445 | 452 | if (id >= 0) |
|---|
| 446 | 453 | p->line = id; |
|---|
| 454 | + |
|---|
| 455 | + if (IS_ENABLED(CONFIG_ROCKCHIP_MINI_KERNEL)) |
|---|
| 456 | + return; |
|---|
| 457 | + |
|---|
| 447 | 458 | #ifdef CONFIG_64BIT |
|---|
| 448 | 459 | if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) { |
|---|
| 449 | 460 | p->serial_in = dw8250_serial_inq; |
|---|
| .. | .. |
|---|
| 469 | 480 | data->uart_16550_compatible = true; |
|---|
| 470 | 481 | } |
|---|
| 471 | 482 | |
|---|
| 483 | + if (IS_ENABLED(CONFIG_ROCKCHIP_MINI_KERNEL)) |
|---|
| 484 | + return; |
|---|
| 485 | + |
|---|
| 472 | 486 | /* Platforms with iDMA 64-bit */ |
|---|
| 473 | 487 | if (platform_get_resource_byname(to_platform_device(p->dev), |
|---|
| 474 | 488 | IORESOURCE_MEM, "lpss_priv")) { |
|---|
| 475 | | - data->dma.rx_param = p->dev->parent; |
|---|
| 476 | | - data->dma.tx_param = p->dev->parent; |
|---|
| 477 | | - data->dma.fn = dw8250_idma_filter; |
|---|
| 489 | + data->data.dma.rx_param = p->dev->parent; |
|---|
| 490 | + data->data.dma.tx_param = p->dev->parent; |
|---|
| 491 | + data->data.dma.fn = dw8250_idma_filter; |
|---|
| 478 | 492 | } |
|---|
| 479 | | -} |
|---|
| 480 | | - |
|---|
| 481 | | -static void dw8250_setup_port(struct uart_port *p) |
|---|
| 482 | | -{ |
|---|
| 483 | | - struct uart_8250_port *up = up_to_u8250p(p); |
|---|
| 484 | | - u32 reg; |
|---|
| 485 | | - |
|---|
| 486 | | - /* |
|---|
| 487 | | - * If the Component Version Register returns zero, we know that |
|---|
| 488 | | - * ADDITIONAL_FEATURES are not enabled. No need to go any further. |
|---|
| 489 | | - */ |
|---|
| 490 | | - reg = dw8250_readl_ext(p, DW_UART_UCV); |
|---|
| 491 | | - if (!reg) |
|---|
| 492 | | - return; |
|---|
| 493 | | - |
|---|
| 494 | | - dev_dbg(p->dev, "Designware UART version %c.%c%c\n", |
|---|
| 495 | | - (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); |
|---|
| 496 | | - |
|---|
| 497 | | - dw8250_writel_ext(p, DW_UART_DLF, ~0U); |
|---|
| 498 | | - reg = dw8250_readl_ext(p, DW_UART_DLF); |
|---|
| 499 | | - dw8250_writel_ext(p, DW_UART_DLF, 0); |
|---|
| 500 | | - |
|---|
| 501 | | - if (reg) { |
|---|
| 502 | | - struct dw8250_data *d = p->private_data; |
|---|
| 503 | | - |
|---|
| 504 | | - d->dlf_size = fls(reg); |
|---|
| 505 | | - p->get_divisor = dw8250_get_divisor; |
|---|
| 506 | | - p->set_divisor = dw8250_set_divisor; |
|---|
| 507 | | - } |
|---|
| 508 | | - |
|---|
| 509 | | - reg = dw8250_readl_ext(p, DW_UART_CPR); |
|---|
| 510 | | - |
|---|
| 511 | | -#ifdef CONFIG_ARCH_ROCKCHIP |
|---|
| 512 | | - /* |
|---|
| 513 | | - * The UART CPR may be 0 of some rockchip soc, |
|---|
| 514 | | - * but it supports fifo and AFC, fifo entry is 32 default. |
|---|
| 515 | | - */ |
|---|
| 516 | | - if (reg == 0) |
|---|
| 517 | | - reg = 0x00023ff2; |
|---|
| 518 | | -#endif |
|---|
| 519 | | - if (!reg) |
|---|
| 520 | | - return; |
|---|
| 521 | | - |
|---|
| 522 | | - /* Select the type based on fifo */ |
|---|
| 523 | | - if (reg & DW_UART_CPR_FIFO_MODE) { |
|---|
| 524 | | - p->type = PORT_16550A; |
|---|
| 525 | | - p->flags |= UPF_FIXED_TYPE; |
|---|
| 526 | | - p->fifosize = DW_UART_CPR_FIFO_SIZE(reg); |
|---|
| 527 | | -#ifdef CONFIG_ARCH_ROCKCHIP |
|---|
| 528 | | - up->tx_loadsz = p->fifosize * 3 / 4; |
|---|
| 529 | | -#endif |
|---|
| 530 | | - up->capabilities = UART_CAP_FIFO; |
|---|
| 531 | | - } |
|---|
| 532 | | - |
|---|
| 533 | | - if (reg & DW_UART_CPR_AFCE_MODE) |
|---|
| 534 | | - up->capabilities |= UART_CAP_AFE; |
|---|
| 535 | | - |
|---|
| 536 | | - if (reg & DW_UART_CPR_SIR_MODE) |
|---|
| 537 | | - up->capabilities |= UART_CAP_IRDA; |
|---|
| 538 | 493 | } |
|---|
| 539 | 494 | |
|---|
| 540 | 495 | static int dw8250_probe(struct platform_device *pdev) |
|---|
| 541 | 496 | { |
|---|
| 542 | | - struct uart_8250_port uart = {}; |
|---|
| 497 | + struct uart_8250_port uart = {}, *up = &uart; |
|---|
| 543 | 498 | struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 544 | | - int irq = platform_get_irq(pdev, 0); |
|---|
| 545 | | - struct uart_port *p = &uart.port; |
|---|
| 499 | + struct uart_port *p = &up->port; |
|---|
| 546 | 500 | struct device *dev = &pdev->dev; |
|---|
| 547 | 501 | struct dw8250_data *data; |
|---|
| 502 | + int irq; |
|---|
| 548 | 503 | int err; |
|---|
| 549 | 504 | u32 val; |
|---|
| 550 | 505 | |
|---|
| .. | .. |
|---|
| 553 | 508 | return -EINVAL; |
|---|
| 554 | 509 | } |
|---|
| 555 | 510 | |
|---|
| 556 | | - if (irq < 0) { |
|---|
| 557 | | - if (irq != -EPROBE_DEFER) |
|---|
| 558 | | - dev_err(dev, "cannot get irq\n"); |
|---|
| 511 | + irq = platform_get_irq(pdev, 0); |
|---|
| 512 | + if (irq < 0) |
|---|
| 559 | 513 | return irq; |
|---|
| 560 | | - } |
|---|
| 561 | 514 | |
|---|
| 562 | 515 | spin_lock_init(&p->lock); |
|---|
| 563 | 516 | p->mapbase = regs->start; |
|---|
| .. | .. |
|---|
| 581 | 534 | if (!data) |
|---|
| 582 | 535 | return -ENOMEM; |
|---|
| 583 | 536 | |
|---|
| 584 | | - data->dma.fn = dw8250_fallback_dma_filter; |
|---|
| 537 | + data->data.dma.fn = dw8250_fallback_dma_filter; |
|---|
| 585 | 538 | data->usr_reg = DW_UART_USR; |
|---|
| 539 | + p->private_data = &data->data; |
|---|
| 586 | 540 | #ifdef CONFIG_ARCH_ROCKCHIP |
|---|
| 587 | 541 | data->irq = irq; |
|---|
| 588 | 542 | #endif |
|---|
| 589 | | - p->private_data = data; |
|---|
| 590 | 543 | |
|---|
| 591 | 544 | data->uart_16550_compatible = device_property_read_bool(dev, |
|---|
| 592 | 545 | "snps,uart-16550-compatible"); |
|---|
| .. | .. |
|---|
| 637 | 590 | device_property_read_u32(dev, "clock-frequency", &p->uartclk); |
|---|
| 638 | 591 | |
|---|
| 639 | 592 | /* If there is separate baudclk, get the rate from it. */ |
|---|
| 640 | | - data->clk = devm_clk_get(dev, "baudclk"); |
|---|
| 641 | | - if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER) |
|---|
| 642 | | - data->clk = devm_clk_get(dev, NULL); |
|---|
| 643 | | - if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) |
|---|
| 644 | | - return -EPROBE_DEFER; |
|---|
| 645 | | - if (!IS_ERR_OR_NULL(data->clk)) { |
|---|
| 646 | | - err = clk_prepare_enable(data->clk); |
|---|
| 647 | | - if (err) |
|---|
| 648 | | - dev_warn(dev, "could not enable optional baudclk: %d\n", |
|---|
| 649 | | - err); |
|---|
| 650 | | - else |
|---|
| 651 | | - p->uartclk = clk_get_rate(data->clk); |
|---|
| 652 | | - } |
|---|
| 593 | + data->clk = devm_clk_get_optional(dev, "baudclk"); |
|---|
| 594 | + if (data->clk == NULL) |
|---|
| 595 | + data->clk = devm_clk_get_optional(dev, NULL); |
|---|
| 596 | + if (IS_ERR(data->clk)) |
|---|
| 597 | + return PTR_ERR(data->clk); |
|---|
| 598 | + |
|---|
| 599 | + INIT_WORK(&data->clk_work, dw8250_clk_work_cb); |
|---|
| 600 | + data->clk_notifier.notifier_call = dw8250_clk_notifier_cb; |
|---|
| 601 | + |
|---|
| 602 | + err = clk_prepare_enable(data->clk); |
|---|
| 603 | + if (err) |
|---|
| 604 | + dev_warn(dev, "could not enable optional baudclk: %d\n", err); |
|---|
| 605 | + |
|---|
| 606 | + if (data->clk) |
|---|
| 607 | + p->uartclk = clk_get_rate(data->clk); |
|---|
| 653 | 608 | |
|---|
| 654 | 609 | /* If no clock rate is defined, fail. */ |
|---|
| 655 | 610 | if (!p->uartclk) { |
|---|
| .. | .. |
|---|
| 658 | 613 | goto err_clk; |
|---|
| 659 | 614 | } |
|---|
| 660 | 615 | |
|---|
| 661 | | - data->pclk = devm_clk_get(dev, "apb_pclk"); |
|---|
| 662 | | - if (IS_ERR(data->pclk) && PTR_ERR(data->pclk) == -EPROBE_DEFER) { |
|---|
| 663 | | - err = -EPROBE_DEFER; |
|---|
| 616 | + data->pclk = devm_clk_get_optional(dev, "apb_pclk"); |
|---|
| 617 | + if (IS_ERR(data->pclk)) { |
|---|
| 618 | + err = PTR_ERR(data->pclk); |
|---|
| 664 | 619 | goto err_clk; |
|---|
| 665 | 620 | } |
|---|
| 666 | | - if (!IS_ERR(data->pclk)) { |
|---|
| 667 | | - err = clk_prepare_enable(data->pclk); |
|---|
| 668 | | - if (err) { |
|---|
| 669 | | - dev_err(dev, "could not enable apb_pclk\n"); |
|---|
| 670 | | - goto err_clk; |
|---|
| 671 | | - } |
|---|
| 621 | + |
|---|
| 622 | + err = clk_prepare_enable(data->pclk); |
|---|
| 623 | + if (err) { |
|---|
| 624 | + dev_err(dev, "could not enable apb_pclk\n"); |
|---|
| 625 | + goto err_clk; |
|---|
| 672 | 626 | } |
|---|
| 673 | 627 | |
|---|
| 674 | 628 | data->rst = devm_reset_control_get_optional_exclusive(dev, NULL); |
|---|
| .. | .. |
|---|
| 689 | 643 | |
|---|
| 690 | 644 | /* If we have a valid fifosize, try hooking up DMA */ |
|---|
| 691 | 645 | if (p->fifosize) { |
|---|
| 692 | | - data->dma.rxconf.src_maxburst = p->fifosize / 4; |
|---|
| 693 | | - data->dma.txconf.dst_maxburst = p->fifosize / 4; |
|---|
| 694 | | - uart.dma = &data->dma; |
|---|
| 646 | + data->data.dma.rxconf.src_maxburst = p->fifosize / 4; |
|---|
| 647 | + data->data.dma.txconf.dst_maxburst = p->fifosize / 4; |
|---|
| 648 | + up->dma = &data->data.dma; |
|---|
| 695 | 649 | } |
|---|
| 696 | 650 | |
|---|
| 697 | | - data->line = serial8250_register_8250_port(&uart); |
|---|
| 698 | | - if (data->line < 0) { |
|---|
| 699 | | - err = data->line; |
|---|
| 651 | + data->data.line = serial8250_register_8250_port(up); |
|---|
| 652 | + if (data->data.line < 0) { |
|---|
| 653 | + err = data->data.line; |
|---|
| 700 | 654 | goto err_reset; |
|---|
| 701 | 655 | } |
|---|
| 702 | 656 | |
|---|
| 657 | + /* |
|---|
| 658 | + * Some platforms may provide a reference clock shared between several |
|---|
| 659 | + * devices. In this case any clock state change must be known to the |
|---|
| 660 | + * UART port at least post factum. |
|---|
| 661 | + */ |
|---|
| 662 | + if (data->clk) { |
|---|
| 663 | + err = clk_notifier_register(data->clk, &data->clk_notifier); |
|---|
| 664 | + if (err) |
|---|
| 665 | + dev_warn(p->dev, "Failed to set the clock notifier\n"); |
|---|
| 666 | + else |
|---|
| 667 | + queue_work(system_unbound_wq, &data->clk_work); |
|---|
| 668 | + } |
|---|
| 703 | 669 | #ifdef CONFIG_ARCH_ROCKCHIP |
|---|
| 704 | 670 | if (data->enable_wakeup) |
|---|
| 705 | 671 | device_init_wakeup(&pdev->dev, true); |
|---|
| 706 | 672 | #endif |
|---|
| 707 | | - |
|---|
| 708 | 673 | platform_set_drvdata(pdev, data); |
|---|
| 709 | 674 | |
|---|
| 710 | 675 | pm_runtime_set_active(dev); |
|---|
| .. | .. |
|---|
| 716 | 681 | reset_control_assert(data->rst); |
|---|
| 717 | 682 | |
|---|
| 718 | 683 | err_pclk: |
|---|
| 719 | | - if (!IS_ERR(data->pclk)) |
|---|
| 720 | | - clk_disable_unprepare(data->pclk); |
|---|
| 684 | + clk_disable_unprepare(data->pclk); |
|---|
| 721 | 685 | |
|---|
| 722 | 686 | err_clk: |
|---|
| 723 | | - if (!IS_ERR(data->clk)) |
|---|
| 724 | | - clk_disable_unprepare(data->clk); |
|---|
| 687 | + clk_disable_unprepare(data->clk); |
|---|
| 725 | 688 | |
|---|
| 726 | 689 | return err; |
|---|
| 727 | 690 | } |
|---|
| .. | .. |
|---|
| 729 | 692 | static int dw8250_remove(struct platform_device *pdev) |
|---|
| 730 | 693 | { |
|---|
| 731 | 694 | struct dw8250_data *data = platform_get_drvdata(pdev); |
|---|
| 695 | + struct device *dev = &pdev->dev; |
|---|
| 732 | 696 | |
|---|
| 733 | | - pm_runtime_get_sync(&pdev->dev); |
|---|
| 697 | + pm_runtime_get_sync(dev); |
|---|
| 734 | 698 | |
|---|
| 735 | | - serial8250_unregister_port(data->line); |
|---|
| 699 | + if (data->clk) { |
|---|
| 700 | + clk_notifier_unregister(data->clk, &data->clk_notifier); |
|---|
| 701 | + |
|---|
| 702 | + flush_work(&data->clk_work); |
|---|
| 703 | + } |
|---|
| 704 | + |
|---|
| 705 | + serial8250_unregister_port(data->data.line); |
|---|
| 736 | 706 | |
|---|
| 737 | 707 | reset_control_assert(data->rst); |
|---|
| 738 | 708 | |
|---|
| 739 | | - if (!IS_ERR(data->pclk)) |
|---|
| 740 | | - clk_disable_unprepare(data->pclk); |
|---|
| 709 | + clk_disable_unprepare(data->pclk); |
|---|
| 741 | 710 | |
|---|
| 742 | | - if (!IS_ERR(data->clk)) |
|---|
| 743 | | - clk_disable_unprepare(data->clk); |
|---|
| 711 | + clk_disable_unprepare(data->clk); |
|---|
| 744 | 712 | |
|---|
| 713 | + pm_runtime_disable(dev); |
|---|
| 714 | + pm_runtime_put_noidle(dev); |
|---|
| 745 | 715 | #ifdef CONFIG_ARCH_ROCKCHIP |
|---|
| 746 | 716 | if (data->enable_wakeup) |
|---|
| 747 | 717 | device_init_wakeup(&pdev->dev, false); |
|---|
| 748 | 718 | #endif |
|---|
| 749 | | - |
|---|
| 750 | | - pm_runtime_disable(&pdev->dev); |
|---|
| 751 | | - pm_runtime_put_noidle(&pdev->dev); |
|---|
| 752 | 719 | |
|---|
| 753 | 720 | return 0; |
|---|
| 754 | 721 | } |
|---|
| .. | .. |
|---|
| 765 | 732 | return 0; |
|---|
| 766 | 733 | } |
|---|
| 767 | 734 | #endif |
|---|
| 768 | | - serial8250_suspend_port(data->line); |
|---|
| 735 | + serial8250_suspend_port(data->data.line); |
|---|
| 769 | 736 | |
|---|
| 770 | 737 | return 0; |
|---|
| 771 | 738 | } |
|---|
| .. | .. |
|---|
| 783 | 750 | return 0; |
|---|
| 784 | 751 | } |
|---|
| 785 | 752 | #endif |
|---|
| 786 | | - serial8250_resume_port(data->line); |
|---|
| 753 | + serial8250_resume_port(data->data.line); |
|---|
| 787 | 754 | |
|---|
| 788 | 755 | return 0; |
|---|
| 789 | 756 | } |
|---|
| .. | .. |
|---|
| 794 | 761 | { |
|---|
| 795 | 762 | struct dw8250_data *data = dev_get_drvdata(dev); |
|---|
| 796 | 763 | |
|---|
| 797 | | - if (!IS_ERR(data->clk)) |
|---|
| 798 | | - clk_disable_unprepare(data->clk); |
|---|
| 764 | + clk_disable_unprepare(data->clk); |
|---|
| 799 | 765 | |
|---|
| 800 | | - if (!IS_ERR(data->pclk)) |
|---|
| 801 | | - clk_disable_unprepare(data->pclk); |
|---|
| 766 | + clk_disable_unprepare(data->pclk); |
|---|
| 802 | 767 | |
|---|
| 803 | 768 | return 0; |
|---|
| 804 | 769 | } |
|---|
| .. | .. |
|---|
| 807 | 772 | { |
|---|
| 808 | 773 | struct dw8250_data *data = dev_get_drvdata(dev); |
|---|
| 809 | 774 | |
|---|
| 810 | | - if (!IS_ERR(data->pclk)) |
|---|
| 811 | | - clk_prepare_enable(data->pclk); |
|---|
| 775 | + clk_prepare_enable(data->pclk); |
|---|
| 812 | 776 | |
|---|
| 813 | | - if (!IS_ERR(data->clk)) |
|---|
| 814 | | - clk_prepare_enable(data->clk); |
|---|
| 777 | + clk_prepare_enable(data->clk); |
|---|
| 815 | 778 | |
|---|
| 816 | 779 | return 0; |
|---|
| 817 | 780 | } |
|---|
| .. | .. |
|---|
| 824 | 787 | |
|---|
| 825 | 788 | static const struct of_device_id dw8250_of_match[] = { |
|---|
| 826 | 789 | { .compatible = "snps,dw-apb-uart" }, |
|---|
| 790 | +#ifndef CONFIG_ROCKCHIP_MINI_KERNEL |
|---|
| 827 | 791 | { .compatible = "cavium,octeon-3860-uart" }, |
|---|
| 828 | 792 | { .compatible = "marvell,armada-38x-uart" }, |
|---|
| 829 | 793 | { .compatible = "renesas,rzn1-uart" }, |
|---|
| 794 | +#endif |
|---|
| 830 | 795 | { /* Sentinel */ } |
|---|
| 831 | 796 | }; |
|---|
| 832 | 797 | MODULE_DEVICE_TABLE(of, dw8250_of_match); |
|---|
| .. | .. |
|---|
| 841 | 806 | { "APMC0D08", 0}, |
|---|
| 842 | 807 | { "AMD0020", 0 }, |
|---|
| 843 | 808 | { "AMDI0020", 0 }, |
|---|
| 809 | + { "AMDI0022", 0 }, |
|---|
| 844 | 810 | { "BRCM2032", 0 }, |
|---|
| 845 | 811 | { "HISI0031", 0 }, |
|---|
| 846 | 812 | { }, |
|---|