^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * arch/arm/mach-lpc32xx/serial.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Author: Kevin Wells <kevin.wells@nxp.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2010 NXP Semiconductors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/serial.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/serial_core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/serial_reg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/serial_8250.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "lpc32xx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define LPC32XX_SUART_FIFO_SIZE 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct uartinit {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) char *uart_ck_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) u32 ck_mode_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) void __iomem *pdiv_clk_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) resource_size_t mapbase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static struct uartinit uartinit_data[] __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) .uart_ck_name = "uart5_ck",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) .ck_mode_mask =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 5),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) .pdiv_clk_reg = LPC32XX_CLKPWR_UART5_CLK_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) .mapbase = LPC32XX_UART5_BASE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) .uart_ck_name = "uart3_ck",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) .ck_mode_mask =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) .pdiv_clk_reg = LPC32XX_CLKPWR_UART3_CLK_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) .mapbase = LPC32XX_UART3_BASE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) .uart_ck_name = "uart4_ck",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) .ck_mode_mask =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 4),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) .pdiv_clk_reg = LPC32XX_CLKPWR_UART4_CLK_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) .mapbase = LPC32XX_UART4_BASE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) .uart_ck_name = "uart6_ck",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) .ck_mode_mask =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 6),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) .pdiv_clk_reg = LPC32XX_CLKPWR_UART6_CLK_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) .mapbase = LPC32XX_UART6_BASE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* LPC3250 Errata HSUART.1: Hang workaround via loopback mode on inactivity */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) void lpc32xx_loopback_set(resource_size_t mapbase, int state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) int bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) u32 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) switch (mapbase) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) case LPC32XX_HS_UART1_BASE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) bit = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) case LPC32XX_HS_UART2_BASE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) bit = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) case LPC32XX_HS_UART7_BASE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) bit = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) WARN(1, "lpc32xx_hs: Warning: Unknown port at %08x\n", mapbase);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) tmp = readl(LPC32XX_UARTCTL_CLOOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) tmp |= (1 << bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) tmp &= ~(1 << bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) writel(tmp, LPC32XX_UARTCTL_CLOOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) EXPORT_SYMBOL_GPL(lpc32xx_loopback_set);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) void __init lpc32xx_serial_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) u32 tmp, clkmodes = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) unsigned int puart;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) int i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) clk = clk_get(NULL, uartinit_data[i].uart_ck_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (!IS_ERR(clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) clk_enable(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /* Setup UART clock modes for all UARTs, disable autoclock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) clkmodes |= uartinit_data[i].ck_mode_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /* pre-UART clock divider set to 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) __raw_writel(0x0101, uartinit_data[i].pdiv_clk_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * Force a flush of the RX FIFOs to work around a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * HW bug
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) puart = uartinit_data[i].mapbase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) __raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) j = LPC32XX_SUART_FIFO_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) while (j--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) tmp = __raw_readl(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) LPC32XX_UART_DLL_FIFO(puart));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) __raw_writel(0, LPC32XX_UART_IIR_FCR(puart));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /* This needs to be done after all UART clocks are setup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) __raw_writel(clkmodes, LPC32XX_UARTCTL_CLKMODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /* Force a flush of the RX FIFOs to work around a HW bug */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) puart = uartinit_data[i].mapbase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) __raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) j = LPC32XX_SUART_FIFO_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) while (j--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) tmp = __raw_readl(LPC32XX_UART_DLL_FIFO(puart));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) __raw_writel(0, LPC32XX_UART_IIR_FCR(puart));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /* Disable IrDA pulsing support on UART6 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) tmp = __raw_readl(LPC32XX_UARTCTL_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) tmp |= LPC32XX_UART_UART6_IRDAMOD_BYPASS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) __raw_writel(tmp, LPC32XX_UARTCTL_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /* Disable UART5->USB transparent mode or USB won't work */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) tmp = __raw_readl(LPC32XX_UARTCTL_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) tmp &= ~LPC32XX_UART_U5_ROUTE_TO_USB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) __raw_writel(tmp, LPC32XX_UARTCTL_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }