cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

udbg_16550.c (7128B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * udbg for NS16550 compatible serial ports
      4 *
      5 * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
      6 */
      7#include <linux/types.h>
      8#include <asm/udbg.h>
      9#include <asm/io.h>
     10#include <asm/reg_a2.h>
     11
     12extern u8 real_readb(volatile u8 __iomem  *addr);
     13extern void real_writeb(u8 data, volatile u8 __iomem *addr);
     14extern u8 real_205_readb(volatile u8 __iomem  *addr);
     15extern void real_205_writeb(u8 data, volatile u8 __iomem *addr);
     16
     17#define UART_RBR	0
     18#define UART_IER	1
     19#define UART_FCR	2
     20#define UART_LCR	3
     21#define UART_MCR	4
     22#define UART_LSR	5
     23#define UART_MSR	6
     24#define UART_SCR	7
     25#define UART_THR	UART_RBR
     26#define UART_IIR	UART_FCR
     27#define UART_DLL	UART_RBR
     28#define UART_DLM	UART_IER
     29#define UART_DLAB	UART_LCR
     30
     31#define LSR_DR   0x01  /* Data ready */
     32#define LSR_OE   0x02  /* Overrun */
     33#define LSR_PE   0x04  /* Parity error */
     34#define LSR_FE   0x08  /* Framing error */
     35#define LSR_BI   0x10  /* Break */
     36#define LSR_THRE 0x20  /* Xmit holding register empty */
     37#define LSR_TEMT 0x40  /* Xmitter empty */
     38#define LSR_ERR  0x80  /* Error */
     39
     40#define LCR_DLAB 0x80
     41
     42static u8 (*udbg_uart_in)(unsigned int reg);
     43static void (*udbg_uart_out)(unsigned int reg, u8 data);
     44
     45static void udbg_uart_flush(void)
     46{
     47	if (!udbg_uart_in)
     48		return;
     49
     50	/* wait for idle */
     51	while ((udbg_uart_in(UART_LSR) & LSR_THRE) == 0)
     52		cpu_relax();
     53}
     54
     55static void udbg_uart_putc(char c)
     56{
     57	if (!udbg_uart_out)
     58		return;
     59
     60	if (c == '\n')
     61		udbg_uart_putc('\r');
     62	udbg_uart_flush();
     63	udbg_uart_out(UART_THR, c);
     64}
     65
     66static int udbg_uart_getc_poll(void)
     67{
     68	if (!udbg_uart_in)
     69		return -1;
     70
     71	if (!(udbg_uart_in(UART_LSR) & LSR_DR))
     72		return udbg_uart_in(UART_RBR);
     73
     74	return -1;
     75}
     76
     77static int udbg_uart_getc(void)
     78{
     79	if (!udbg_uart_in)
     80		return -1;
     81	/* wait for char */
     82	while (!(udbg_uart_in(UART_LSR) & LSR_DR))
     83		cpu_relax();
     84	return udbg_uart_in(UART_RBR);
     85}
     86
     87static void __init udbg_use_uart(void)
     88{
     89	udbg_putc = udbg_uart_putc;
     90	udbg_flush = udbg_uart_flush;
     91	udbg_getc = udbg_uart_getc;
     92	udbg_getc_poll = udbg_uart_getc_poll;
     93}
     94
     95void __init udbg_uart_setup(unsigned int speed, unsigned int clock)
     96{
     97	unsigned int dll, base_bauds;
     98
     99	if (!udbg_uart_out)
    100		return;
    101
    102	if (clock == 0)
    103		clock = 1843200;
    104	if (speed == 0)
    105		speed = 9600;
    106
    107	base_bauds = clock / 16;
    108	dll = base_bauds / speed;
    109
    110	udbg_uart_out(UART_LCR, 0x00);
    111	udbg_uart_out(UART_IER, 0xff);
    112	udbg_uart_out(UART_IER, 0x00);
    113	udbg_uart_out(UART_LCR, LCR_DLAB);
    114	udbg_uart_out(UART_DLL, dll & 0xff);
    115	udbg_uart_out(UART_DLM, dll >> 8);
    116	/* 8 data, 1 stop, no parity */
    117	udbg_uart_out(UART_LCR, 0x3);
    118	/* RTS/DTR */
    119	udbg_uart_out(UART_MCR, 0x3);
    120	/* Clear & enable FIFOs */
    121	udbg_uart_out(UART_FCR, 0x7);
    122}
    123
    124unsigned int __init udbg_probe_uart_speed(unsigned int clock)
    125{
    126	unsigned int dll, dlm, divisor, prescaler, speed;
    127	u8 old_lcr;
    128
    129	old_lcr = udbg_uart_in(UART_LCR);
    130
    131	/* select divisor latch registers.  */
    132	udbg_uart_out(UART_LCR, old_lcr | LCR_DLAB);
    133
    134	/* now, read the divisor */
    135	dll = udbg_uart_in(UART_DLL);
    136	dlm = udbg_uart_in(UART_DLM);
    137	divisor = dlm << 8 | dll;
    138
    139	/* check prescaling */
    140	if (udbg_uart_in(UART_MCR) & 0x80)
    141		prescaler = 4;
    142	else
    143		prescaler = 1;
    144
    145	/* restore the LCR */
    146	udbg_uart_out(UART_LCR, old_lcr);
    147
    148	/* calculate speed */
    149	speed = (clock / prescaler) / (divisor * 16);
    150
    151	/* sanity check */
    152	if (speed > (clock / 16))
    153		speed = 9600;
    154
    155	return speed;
    156}
    157
    158static union {
    159	unsigned char __iomem *mmio_base;
    160	unsigned long pio_base;
    161} udbg_uart;
    162
    163static unsigned int udbg_uart_stride = 1;
    164
    165static u8 udbg_uart_in_pio(unsigned int reg)
    166{
    167	return inb(udbg_uart.pio_base + (reg * udbg_uart_stride));
    168}
    169
    170static void udbg_uart_out_pio(unsigned int reg, u8 data)
    171{
    172	outb(data, udbg_uart.pio_base + (reg * udbg_uart_stride));
    173}
    174
    175void __init udbg_uart_init_pio(unsigned long port, unsigned int stride)
    176{
    177	if (!port)
    178		return;
    179	udbg_uart.pio_base = port;
    180	udbg_uart_stride = stride;
    181	udbg_uart_in = udbg_uart_in_pio;
    182	udbg_uart_out = udbg_uart_out_pio;
    183	udbg_use_uart();
    184}
    185
    186static u8 udbg_uart_in_mmio(unsigned int reg)
    187{
    188	return in_8(udbg_uart.mmio_base + (reg * udbg_uart_stride));
    189}
    190
    191static void udbg_uart_out_mmio(unsigned int reg, u8 data)
    192{
    193	out_8(udbg_uart.mmio_base + (reg * udbg_uart_stride), data);
    194}
    195
    196
    197void __init udbg_uart_init_mmio(void __iomem *addr, unsigned int stride)
    198{
    199	if (!addr)
    200		return;
    201	udbg_uart.mmio_base = addr;
    202	udbg_uart_stride = stride;
    203	udbg_uart_in = udbg_uart_in_mmio;
    204	udbg_uart_out = udbg_uart_out_mmio;
    205	udbg_use_uart();
    206}
    207
    208#ifdef CONFIG_PPC_MAPLE
    209
    210#define UDBG_UART_MAPLE_ADDR	((void __iomem *)0xf40003f8)
    211
    212static u8 udbg_uart_in_maple(unsigned int reg)
    213{
    214	return real_readb(UDBG_UART_MAPLE_ADDR + reg);
    215}
    216
    217static void udbg_uart_out_maple(unsigned int reg, u8 val)
    218{
    219	real_writeb(val, UDBG_UART_MAPLE_ADDR + reg);
    220}
    221
    222void __init udbg_init_maple_realmode(void)
    223{
    224	udbg_uart_in = udbg_uart_in_maple;
    225	udbg_uart_out = udbg_uart_out_maple;
    226	udbg_use_uart();
    227}
    228
    229#endif /* CONFIG_PPC_MAPLE */
    230
    231#ifdef CONFIG_PPC_PASEMI
    232
    233#define UDBG_UART_PAS_ADDR	((void __iomem *)0xfcff03f8UL)
    234
    235static u8 udbg_uart_in_pas(unsigned int reg)
    236{
    237	return real_205_readb(UDBG_UART_PAS_ADDR + reg);
    238}
    239
    240static void udbg_uart_out_pas(unsigned int reg, u8 val)
    241{
    242	real_205_writeb(val, UDBG_UART_PAS_ADDR + reg);
    243}
    244
    245void __init udbg_init_pas_realmode(void)
    246{
    247	udbg_uart_in = udbg_uart_in_pas;
    248	udbg_uart_out = udbg_uart_out_pas;
    249	udbg_use_uart();
    250}
    251
    252#endif /* CONFIG_PPC_PASEMI */
    253
    254#ifdef CONFIG_PPC_EARLY_DEBUG_44x
    255
    256#include <platforms/44x/44x.h>
    257
    258static u8 udbg_uart_in_44x_as1(unsigned int reg)
    259{
    260	return as1_readb((void __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR + reg);
    261}
    262
    263static void udbg_uart_out_44x_as1(unsigned int reg, u8 val)
    264{
    265	as1_writeb(val, (void __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR + reg);
    266}
    267
    268void __init udbg_init_44x_as1(void)
    269{
    270	udbg_uart_in = udbg_uart_in_44x_as1;
    271	udbg_uart_out = udbg_uart_out_44x_as1;
    272	udbg_use_uart();
    273}
    274
    275#endif /* CONFIG_PPC_EARLY_DEBUG_44x */
    276
    277#ifdef CONFIG_PPC_EARLY_DEBUG_40x
    278
    279static u8 udbg_uart_in_40x(unsigned int reg)
    280{
    281	return real_readb((void __iomem *)CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR
    282			  + reg);
    283}
    284
    285static void udbg_uart_out_40x(unsigned int reg, u8 val)
    286{
    287	real_writeb(val, (void __iomem *)CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR
    288		    + reg);
    289}
    290
    291void __init udbg_init_40x_realmode(void)
    292{
    293	udbg_uart_in = udbg_uart_in_40x;
    294	udbg_uart_out = udbg_uart_out_40x;
    295	udbg_use_uart();
    296}
    297
    298#endif /* CONFIG_PPC_EARLY_DEBUG_40x */
    299
    300#ifdef CONFIG_PPC_EARLY_DEBUG_MICROWATT
    301
    302#define UDBG_UART_MW_ADDR	((void __iomem *)0xc0002000)
    303
    304static u8 udbg_uart_in_isa300_rm(unsigned int reg)
    305{
    306	uint64_t msr = mfmsr();
    307	uint8_t  c;
    308
    309	mtmsr(msr & ~(MSR_EE|MSR_DR));
    310	isync();
    311	eieio();
    312	c = __raw_rm_readb(UDBG_UART_MW_ADDR + (reg << 2));
    313	mtmsr(msr);
    314	isync();
    315	return c;
    316}
    317
    318static void udbg_uart_out_isa300_rm(unsigned int reg, u8 val)
    319{
    320	uint64_t msr = mfmsr();
    321
    322	mtmsr(msr & ~(MSR_EE|MSR_DR));
    323	isync();
    324	eieio();
    325	__raw_rm_writeb(val, UDBG_UART_MW_ADDR + (reg << 2));
    326	mtmsr(msr);
    327	isync();
    328}
    329
    330void __init udbg_init_debug_microwatt(void)
    331{
    332	udbg_uart_in = udbg_uart_in_isa300_rm;
    333	udbg_uart_out = udbg_uart_out_isa300_rm;
    334	udbg_use_uart();
    335}
    336
    337#endif /* CONFIG_PPC_EARLY_DEBUG_MICROWATT */