1/*
2 * (C) Copyright 2010
3 * Michael Kurz <michi.kurz@googlemail.com>.
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24#include <asm/addrspace.h>
25#include <asm/types.h>
26#include <config.h>
27#include <asm/ar71xx.h>
28
29#define		REG_SIZE		4
30
31/* === END OF CONFIG === */
32
33/* register offset */
34#define         OFS_RCV_BUFFER          (0*REG_SIZE)
35#define         OFS_TRANS_HOLD          (0*REG_SIZE)
36#define         OFS_SEND_BUFFER         (0*REG_SIZE)
37#define         OFS_INTR_ENABLE         (1*REG_SIZE)
38#define         OFS_INTR_ID             (2*REG_SIZE)
39#define         OFS_DATA_FORMAT         (3*REG_SIZE)
40#define         OFS_LINE_CONTROL        (3*REG_SIZE)
41#define         OFS_MODEM_CONTROL       (4*REG_SIZE)
42#define         OFS_RS232_OUTPUT        (4*REG_SIZE)
43#define         OFS_LINE_STATUS         (5*REG_SIZE)
44#define         OFS_MODEM_STATUS        (6*REG_SIZE)
45#define         OFS_RS232_INPUT         (6*REG_SIZE)
46#define         OFS_SCRATCH_PAD         (7*REG_SIZE)
47
48#define         OFS_DIVISOR_LSB         (0*REG_SIZE)
49#define         OFS_DIVISOR_MSB         (1*REG_SIZE)
50
51#define         UART16550_READ(y)   readl(KSEG1ADDR(AR71XX_UART_BASE+y))
52#define         UART16550_WRITE(x, z)  writel(z, KSEG1ADDR((AR71XX_UART_BASE+x)))
53
54void
55ar71xx_sys_frequency(u32 *cpu_freq, u32 *ddr_freq, u32 *ahb_freq)
56{
57#ifndef CONFIG_AR91XX
58    u32 pll, pll_div, cpu_div, ahb_div, ddr_div, freq;
59
60    pll = readl(KSEG1ADDR(AR71XX_PLL_REG_CPU_CONFIG + AR71XX_PLL_BASE));
61
62    pll_div =
63        ((pll & AR71XX_PLL_DIV_MASK) >> AR71XX_PLL_DIV_SHIFT) + 1;
64
65    cpu_div =
66        ((pll & AR71XX_CPU_DIV_MASK) >> AR71XX_CPU_DIV_SHIFT) + 1;
67
68    ddr_div =
69        ((pll & AR71XX_DDR_DIV_MASK) >> AR71XX_DDR_DIV_SHIFT) + 1;
70
71    ahb_div =
72       (((pll & AR71XX_AHB_DIV_MASK) >> AR71XX_AHB_DIV_SHIFT) + 1)*2;
73
74    freq = pll_div * 40000000;
75
76    if (cpu_freq)
77        *cpu_freq = freq/cpu_div;
78
79    if (ddr_freq)
80        *ddr_freq = freq/ddr_div;
81
82    if (ahb_freq)
83        *ahb_freq = (freq/cpu_div)/ahb_div;
84
85#else
86    u32 pll, pll_div, ahb_div, ddr_div, freq;
87
88    pll = readl(KSEG1ADDR(AR91XX_PLL_REG_CPU_CONFIG + AR71XX_PLL_BASE));
89
90    pll_div =
91        ((pll & AR91XX_PLL_DIV_MASK) >> AR91XX_PLL_DIV_SHIFT);
92
93    ddr_div =
94        ((pll & AR91XX_DDR_DIV_MASK) >> AR91XX_DDR_DIV_SHIFT) + 1;
95
96    ahb_div =
97       (((pll & AR91XX_AHB_DIV_MASK) >> AR91XX_AHB_DIV_SHIFT) + 1)*2;
98
99    freq = pll_div * 5000000;
100
101    if (cpu_freq)
102        *cpu_freq = freq;
103
104    if (ddr_freq)
105        *ddr_freq = freq/ddr_div;
106
107    if (ahb_freq)
108        *ahb_freq = freq/ahb_div;
109#endif
110}
111
112
113int serial_init(void)
114{
115    u32 div;
116    u32 ahb_freq = 100000000;
117
118    ar71xx_sys_frequency  (0, 0, &ahb_freq);
119    div  = ahb_freq/(16 * CONFIG_BAUDRATE);
120
121	// enable uart pins
122#ifndef CONFIG_AR91XX
123    writel(AR71XX_GPIO_FUNC_UART_EN, KSEG1ADDR(AR71XX_GPIO_BASE + GPIO_REG_FUNC));
124#else
125	writel(AR91XX_GPIO_FUNC_UART_EN, KSEG1ADDR(AR71XX_GPIO_BASE + GPIO_REG_FUNC));
126#endif
127
128    /* set DIAB bit */
129    UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
130
131    /* set divisor */
132    UART16550_WRITE(OFS_DIVISOR_LSB, (div & 0xff));
133    UART16550_WRITE(OFS_DIVISOR_MSB, ((div >> 8) & 0xff));
134
135    /* clear DIAB bit*/
136    UART16550_WRITE(OFS_LINE_CONTROL, 0x00);
137
138    /* set data format */
139    UART16550_WRITE(OFS_DATA_FORMAT, 0x3);
140
141    UART16550_WRITE(OFS_INTR_ENABLE, 0);
142
143	return 0;
144}
145
146int serial_tstc (void)
147{
148    return(UART16550_READ(OFS_LINE_STATUS) & 0x1);
149}
150
151int serial_getc(void)
152{
153    while(!serial_tstc());
154
155    return UART16550_READ(OFS_RCV_BUFFER);
156}
157
158
159void serial_putc(const char byte)
160{
161    if (byte == '\n') serial_putc ('\r');
162
163    while (((UART16550_READ(OFS_LINE_STATUS)) & 0x20) == 0x0);
164    UART16550_WRITE(OFS_SEND_BUFFER, byte);
165}
166
167void serial_setbrg (void)
168{
169}
170
171void serial_puts (const char *s)
172{
173	while (*s)
174	{
175		serial_putc (*s++);
176	}
177}
178