1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2004-2007 ARM Limited. 4 * Copyright (C) 2008 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> 5 * Copyright (C) 2015 - 2016 Xilinx, Inc, Michal Simek 6 * 7 * As a special exception, if other files instantiate templates or use macros 8 * or inline functions from this file, or you compile this file and link it 9 * with other works to produce a work based on this file, this file does not 10 * by itself cause the resulting work to be covered by the GNU General Public 11 * License. However the source code for this file must still be made available 12 * in accordance with section (3) of the GNU General Public License. 13 14 * This exception does not invalidate any other reasons why a work based on 15 * this file might be covered by the GNU General Public License. 16 */ 17 18 #include <common.h> 19 #include <dm.h> 20 #include <serial.h> 21 22 #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V7A) || defined(CONFIG_CPU_V7R) 23 /* 24 * ARMV6 & ARMV7 25 */ 26 #define DCC_RBIT (1 << 30) 27 #define DCC_WBIT (1 << 29) 28 29 #define write_dcc(x) \ 30 __asm__ volatile ("mcr p14, 0, %0, c0, c5, 0\n" : : "r" (x)) 31 32 #define read_dcc(x) \ 33 __asm__ volatile ("mrc p14, 0, %0, c0, c5, 0\n" : "=r" (x)) 34 35 #define status_dcc(x) \ 36 __asm__ volatile ("mrc p14, 0, %0, c0, c1, 0\n" : "=r" (x)) 37 38 #elif defined(CONFIG_CPU_XSCALE) 39 /* 40 * XSCALE 41 */ 42 #define DCC_RBIT (1 << 31) 43 #define DCC_WBIT (1 << 28) 44 45 #define write_dcc(x) \ 46 __asm__ volatile ("mcr p14, 0, %0, c8, c0, 0\n" : : "r" (x)) 47 48 #define read_dcc(x) \ 49 __asm__ volatile ("mrc p14, 0, %0, c9, c0, 0\n" : "=r" (x)) 50 51 #define status_dcc(x) \ 52 __asm__ volatile ("mrc p14, 0, %0, c14, c0, 0\n" : "=r" (x)) 53 54 #elif defined(CONFIG_CPU_ARMV8) 55 /* 56 * ARMV8 57 */ 58 #define DCC_RBIT (1 << 30) 59 #define DCC_WBIT (1 << 29) 60 61 #define write_dcc(x) \ 62 __asm__ volatile ("msr dbgdtrtx_el0, %0\n" : : "r" (x)) 63 64 #define read_dcc(x) \ 65 __asm__ volatile ("mrs %0, dbgdtrrx_el0\n" : "=r" (x)) 66 67 #define status_dcc(x) \ 68 __asm__ volatile ("mrs %0, mdccsr_el0\n" : "=r" (x)) 69 70 #else 71 #define DCC_RBIT (1 << 0) 72 #define DCC_WBIT (1 << 1) 73 74 #define write_dcc(x) \ 75 __asm__ volatile ("mcr p14, 0, %0, c1, c0, 0\n" : : "r" (x)) 76 77 #define read_dcc(x) \ 78 __asm__ volatile ("mrc p14, 0, %0, c1, c0, 0\n" : "=r" (x)) 79 80 #define status_dcc(x) \ 81 __asm__ volatile ("mrc p14, 0, %0, c0, c0, 0\n" : "=r" (x)) 82 83 #endif 84 85 #define can_read_dcc(x) do { \ 86 status_dcc(x); \ 87 x &= DCC_RBIT; \ 88 } while (0); 89 90 #define can_write_dcc(x) do { \ 91 status_dcc(x); \ 92 x &= DCC_WBIT; \ 93 x = (x == 0); \ 94 } while (0); 95 96 #define TIMEOUT_COUNT 0x4000000 97 98 static int arm_dcc_getc(struct udevice *dev) 99 { 100 int ch; 101 register unsigned int reg; 102 103 do { 104 can_read_dcc(reg); 105 } while (!reg); 106 read_dcc(ch); 107 108 return ch; 109 } 110 111 static int arm_dcc_putc(struct udevice *dev, char ch) 112 { 113 register unsigned int reg; 114 unsigned int timeout_count = TIMEOUT_COUNT; 115 116 while (--timeout_count) { 117 can_write_dcc(reg); 118 if (reg) 119 break; 120 } 121 if (timeout_count == 0) 122 return -EAGAIN; 123 else 124 write_dcc(ch); 125 126 return 0; 127 } 128 129 static int arm_dcc_pending(struct udevice *dev, bool input) 130 { 131 register unsigned int reg; 132 133 if (input) { 134 can_read_dcc(reg); 135 } else { 136 can_write_dcc(reg); 137 } 138 139 return reg; 140 } 141 142 static const struct dm_serial_ops arm_dcc_ops = { 143 .putc = arm_dcc_putc, 144 .pending = arm_dcc_pending, 145 .getc = arm_dcc_getc, 146 }; 147 148 static const struct udevice_id arm_dcc_ids[] = { 149 { .compatible = "arm,dcc", }, 150 { } 151 }; 152 153 U_BOOT_DRIVER(serial_dcc) = { 154 .name = "arm_dcc", 155 .id = UCLASS_SERIAL, 156 .of_match = arm_dcc_ids, 157 .ops = &arm_dcc_ops, 158 .flags = DM_FLAG_PRE_RELOC, 159 }; 160 161 #ifdef CONFIG_DEBUG_UART_ARM_DCC 162 163 #include <debug_uart.h> 164 165 static inline void _debug_uart_init(void) 166 { 167 } 168 169 static inline void _debug_uart_putc(int ch) 170 { 171 arm_dcc_putc(NULL, ch); 172 } 173 174 DEBUG_UART_FUNCS 175 #endif 176