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

ls_uart.c (3500B)


      1/*
      2 * AVR power-management chip interface for the Buffalo Linkstation /
      3 * Kurobox Platform.
      4 *
      5 * Author: 2006 (c) G. Liakhovetski
      6 *	 g.liakhovetski@gmx.de
      7 *
      8 * This file is licensed under the terms of the GNU General Public License
      9 * version 2.  This program is licensed "as is" without any warranty of
     10 * any kind, whether express or implied.
     11 */
     12#include <linux/workqueue.h>
     13#include <linux/string.h>
     14#include <linux/delay.h>
     15#include <linux/serial_reg.h>
     16#include <linux/serial_8250.h>
     17#include <linux/of.h>
     18#include <asm/io.h>
     19#include <asm/termbits.h>
     20
     21#include "mpc10x.h"
     22
     23static void __iomem *avr_addr;
     24static unsigned long avr_clock;
     25
     26static struct work_struct wd_work;
     27
     28static void wd_stop(struct work_struct *unused)
     29{
     30	const char string[] = "AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK";
     31	int i = 0, rescue = 8;
     32	int len = strlen(string);
     33
     34	while (rescue--) {
     35		int j;
     36		char lsr = in_8(avr_addr + UART_LSR);
     37
     38		if (lsr & (UART_LSR_THRE | UART_LSR_TEMT)) {
     39			for (j = 0; j < 16 && i < len; j++, i++)
     40				out_8(avr_addr + UART_TX, string[i]);
     41			if (i == len) {
     42				/* Read "OK" back: 4ms for the last "KKKK"
     43				   plus a couple bytes back */
     44				msleep(7);
     45				printk("linkstation: disarming the AVR watchdog: ");
     46				while (in_8(avr_addr + UART_LSR) & UART_LSR_DR)
     47					printk("%c", in_8(avr_addr + UART_RX));
     48				break;
     49			}
     50		}
     51		msleep(17);
     52	}
     53	printk("\n");
     54}
     55
     56#define AVR_QUOT(clock) ((clock) + 8 * 9600) / (16 * 9600)
     57
     58void avr_uart_configure(void)
     59{
     60	unsigned char cval = UART_LCR_WLEN8;
     61	unsigned int quot = AVR_QUOT(avr_clock);
     62
     63	if (!avr_addr || !avr_clock)
     64		return;
     65
     66	out_8(avr_addr + UART_LCR, cval);			/* initialise UART */
     67	out_8(avr_addr + UART_MCR, 0);
     68	out_8(avr_addr + UART_IER, 0);
     69
     70	cval |= UART_LCR_STOP | UART_LCR_PARITY | UART_LCR_EPAR;
     71
     72	out_8(avr_addr + UART_LCR, cval);			/* Set character format */
     73
     74	out_8(avr_addr + UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */
     75	out_8(avr_addr + UART_DLL, quot & 0xff);		/* LS of divisor */
     76	out_8(avr_addr + UART_DLM, quot >> 8);			/* MS of divisor */
     77	out_8(avr_addr + UART_LCR, cval);			/* reset DLAB */
     78	out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO);	/* enable FIFO */
     79}
     80
     81void avr_uart_send(const char c)
     82{
     83	if (!avr_addr || !avr_clock)
     84		return;
     85
     86	out_8(avr_addr + UART_TX, c);
     87	out_8(avr_addr + UART_TX, c);
     88	out_8(avr_addr + UART_TX, c);
     89	out_8(avr_addr + UART_TX, c);
     90}
     91
     92static void __init ls_uart_init(void)
     93{
     94	local_irq_disable();
     95
     96#ifndef CONFIG_SERIAL_8250
     97	out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO);	/* enable FIFO */
     98	out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO |
     99	      UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);	/* clear FIFOs */
    100	out_8(avr_addr + UART_FCR, 0);
    101	out_8(avr_addr + UART_IER, 0);
    102
    103	/* Clear up interrupts */
    104	(void) in_8(avr_addr + UART_LSR);
    105	(void) in_8(avr_addr + UART_RX);
    106	(void) in_8(avr_addr + UART_IIR);
    107	(void) in_8(avr_addr + UART_MSR);
    108#endif
    109	avr_uart_configure();
    110
    111	local_irq_enable();
    112}
    113
    114static int __init ls_uarts_init(void)
    115{
    116	struct device_node *avr;
    117	phys_addr_t phys_addr;
    118	int len;
    119
    120	avr = of_find_node_by_path("/soc10x/serial@80004500");
    121	if (!avr)
    122		return -EINVAL;
    123
    124	avr_clock = *(u32*)of_get_property(avr, "clock-frequency", &len);
    125	phys_addr = ((u32*)of_get_property(avr, "reg", &len))[0];
    126
    127	if (!avr_clock || !phys_addr)
    128		return -EINVAL;
    129
    130	avr_addr = ioremap(phys_addr, 32);
    131	if (!avr_addr)
    132		return -EFAULT;
    133
    134	ls_uart_init();
    135
    136	INIT_WORK(&wd_work, wd_stop);
    137	schedule_work(&wd_work);
    138
    139	return 0;
    140}
    141
    142machine_late_initcall(linkstation, ls_uarts_init);