Linux Audio
Check our new training course
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
// SPDX-License-Identifier: GPL-2.0-only /* * Atheros AR7XXX/AR9XXX SoC early printk support * * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> */ #include <linux/io.h> #include <linux/errno.h> #include <linux/serial.h> #include <linux/serial_reg.h> #include <asm/addrspace.h> #include <asm/setup.h> #include <asm/mach-ath79/ath79.h> #include <asm/mach-ath79/ar71xx_regs.h> #include <asm/mach-ath79/ar933x_uart.h> static void (*_prom_putchar)(char); static inline void prom_putchar_wait(void __iomem *reg, u32 val) { u32 t; do { t = __raw_readl(reg); if ((t & val) == val) break; } while (1); } static void prom_putchar_ar71xx(char ch) { void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE)); prom_putchar_wait(base + UART_LSR * 4, UART_LSR_BOTH_EMPTY); __raw_writel((unsigned char)ch, base + UART_TX * 4); prom_putchar_wait(base + UART_LSR * 4, UART_LSR_BOTH_EMPTY); } static void prom_putchar_ar933x(char ch) { void __iomem *base = (void __iomem *)(KSEG1ADDR(AR933X_UART_BASE)); prom_putchar_wait(base + AR933X_UART_DATA_REG, AR933X_UART_DATA_TX_CSR); __raw_writel(AR933X_UART_DATA_TX_CSR | (unsigned char)ch, base + AR933X_UART_DATA_REG); prom_putchar_wait(base + AR933X_UART_DATA_REG, AR933X_UART_DATA_TX_CSR); } static void prom_putchar_dummy(char ch) { /* nothing to do */ } static void prom_enable_uart(u32 id) { void __iomem *gpio_base; u32 uart_en; u32 t; switch (id) { case REV_ID_MAJOR_AR71XX: uart_en = AR71XX_GPIO_FUNC_UART_EN; break; case REV_ID_MAJOR_AR7240: case REV_ID_MAJOR_AR7241: case REV_ID_MAJOR_AR7242: uart_en = AR724X_GPIO_FUNC_UART_EN; break; case REV_ID_MAJOR_AR913X: uart_en = AR913X_GPIO_FUNC_UART_EN; break; case REV_ID_MAJOR_AR9330: case REV_ID_MAJOR_AR9331: uart_en = AR933X_GPIO_FUNC_UART_EN; break; case REV_ID_MAJOR_AR9341: case REV_ID_MAJOR_AR9342: case REV_ID_MAJOR_AR9344: /* TODO */ default: return; } gpio_base = (void __iomem *)KSEG1ADDR(AR71XX_GPIO_BASE); t = __raw_readl(gpio_base + AR71XX_GPIO_REG_FUNC); t |= uart_en; __raw_writel(t, gpio_base + AR71XX_GPIO_REG_FUNC); } static void prom_putchar_init(void) { void __iomem *base; u32 id; base = (void __iomem *)(KSEG1ADDR(AR71XX_RESET_BASE)); id = __raw_readl(base + AR71XX_RESET_REG_REV_ID); id &= REV_ID_MAJOR_MASK; switch (id) { case REV_ID_MAJOR_AR71XX: case REV_ID_MAJOR_AR7240: case REV_ID_MAJOR_AR7241: case REV_ID_MAJOR_AR7242: case REV_ID_MAJOR_AR913X: case REV_ID_MAJOR_AR9341: case REV_ID_MAJOR_AR9342: case REV_ID_MAJOR_AR9344: case REV_ID_MAJOR_QCA9533: case REV_ID_MAJOR_QCA9533_V2: case REV_ID_MAJOR_QCA9556: case REV_ID_MAJOR_QCA9558: case REV_ID_MAJOR_TP9343: case REV_ID_MAJOR_QCA956X: case REV_ID_MAJOR_QCN550X: _prom_putchar = prom_putchar_ar71xx; break; case REV_ID_MAJOR_AR9330: case REV_ID_MAJOR_AR9331: _prom_putchar = prom_putchar_ar933x; break; default: _prom_putchar = prom_putchar_dummy; return; } prom_enable_uart(id); } void prom_putchar(char ch) { if (!_prom_putchar) prom_putchar_init(); _prom_putchar(ch); }