ingenic_com.c revision 1.2 1 /* $NetBSD: ingenic_com.c,v 1.2 2014/12/06 14:33:18 macallan Exp $ */
2
3 /*-
4 * Copyright (c) 2014 Michael Lorenz
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: ingenic_com.c,v 1.2 2014/12/06 14:33:18 macallan Exp $");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/device.h>
35 #include <sys/kernel.h>
36 #include <sys/termios.h>
37 #include <sys/ttydefaults.h>
38 #include <sys/types.h>
39
40 #include <sys/bus.h>
41
42 #include <dev/cons.h>
43 #include <dev/ic/comreg.h>
44 #include <dev/ic/comvar.h>
45
46 #include <mips/cpuregs.h>
47
48 #include <mips/ingenic/ingenic_regs.h>
49
50 #include "opt_com.h"
51
52 volatile int32_t *com0addr = (int32_t *)MIPS_PHYS_TO_KSEG1(JZ_UART0);
53
54 void ingenic_putchar_init(void);
55 void ingenic_puts(const char *);
56 void ingenic_putchar(char);
57
58 #ifndef CONMODE
59 # define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8)
60 #endif
61
62
63 static struct mips_bus_space ingenic_com_mbst;
64 static int mbst_valid = 0;
65 static void ingenic_com_bus_mem_init(bus_space_tag_t, void *);
66 void ingenic_com_cnattach(void);
67
68 static int ingenic_com_match(device_t, cfdata_t , void *);
69 static void ingenic_com_attach(device_t, device_t, void *);
70
71 struct ingenic_com_softc {
72 struct com_softc sc_com;
73 };
74
75 CFATTACH_DECL_NEW(com_mainbus, sizeof(struct ingenic_com_softc),
76 ingenic_com_match, ingenic_com_attach, NULL, NULL);
77
78 bus_space_handle_t regh = 0;
79
80 void
81 ingenic_putchar_init(void)
82 {
83 /*
84 * XXX don't screw with the UART's speed until we know what clock
85 * we're on
86 */
87 #if 0
88 int rate;
89 #endif
90 extern int comspeed(long, long, int);
91
92 com0addr = (uint32_t *)MIPS_PHYS_TO_KSEG1(JZ_UART0);
93 #if 0
94 if (comcnfreq != -1) {
95 rate = comspeed(comcnspeed, comcnfreq, COM_TYPE_INGENIC);
96 if (rate < 0)
97 return; /* XXX */
98 #endif
99 com0addr[com_ier] = 0;
100 com0addr[com_lctl] = htole32(LCR_DLAB);
101 #if 0
102 com0addr[com_dlbl] = htole32(rate & 0xff);
103 com0addr[com_dlbh] = htole32(rate >> 8);
104 #endif
105 com0addr[com_lctl] = htole32(LCR_8BITS); /* XXX */
106 com0addr[com_mcr] = htole32(MCR_DTR|MCR_RTS);
107 com0addr[com_fifo] = htole32(
108 FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
109 FIFO_TRIGGER_1 | FIFO_UART_ON);
110 #if 0
111 }
112 #endif
113 }
114
115
116 void
117 ingenic_putchar(char c)
118 {
119 int timo = 150000;
120
121 while ((le32toh(com0addr[com_lsr]) & LSR_TXRDY) == 0)
122 if (--timo == 0)
123 break;
124
125 com0addr[com_data] = htole32((uint32_t)c);
126
127 while ((le32toh(com0addr[com_lsr]) & LSR_TSRE) == 0)
128 if (--timo == 0)
129 break;
130 }
131
132 void
133 ingenic_puts(const char *restrict s)
134 {
135 char c;
136
137 while ((c = *s++) != 0)
138 ingenic_putchar(c);
139 }
140
141 static void
142 ingenic_com_bus_init(void)
143 {
144 if (mbst_valid) return;
145 ingenic_com_bus_mem_init(&ingenic_com_mbst, NULL);
146 mbst_valid = 1;
147 }
148
149 void
150 ingenic_com_cnattach(void)
151 {
152 struct com_regs regs;
153
154 ingenic_com_bus_init();
155 bus_space_map(&ingenic_com_mbst, 0, 0x1000, 0, ®h);
156
157 memset(®s, 0, sizeof(regs));
158 COM_INIT_REGS(regs, &ingenic_com_mbst, regh, 0);
159
160 /*
161 * XXX
162 * UART clock is either 6MHz or 12MHz, the manual is rather unclear
163 * so we just leave alone whatever u-boot set up
164 * my uplcom is too tolerant to show any difference
165 */
166 comcnattach1(®s, -1, 6000000, COM_TYPE_INGENIC, CONMODE);
167 }
168
169 static int
170 ingenic_com_match(device_t parent, cfdata_t cfdata, void *args)
171 {
172 struct mainbusdev {
173 const char *md_name;
174 } *aa = args;
175 if (strcmp(aa->md_name, "com") == 0) return 1;
176 return 0;
177 }
178
179
180 static void
181 ingenic_com_attach(device_t parent, device_t self, void *args)
182 {
183 struct ingenic_com_softc *isc = device_private(self);
184 struct com_softc *sc = &isc->sc_com;
185
186 sc->sc_dev = self;
187 sc->sc_frequency = 12000000;
188 sc->sc_type = COM_TYPE_INGENIC;
189 memset(&sc->sc_regs, 0, sizeof(sc->sc_regs));
190 COM_INIT_REGS(sc->sc_regs, &ingenic_com_mbst, regh, 0);
191 com_attach_subr(sc);
192 printf("\n");
193 /* interrupt */
194 }
195
196 #define CHIP ingenic_com
197 #define CHIP_MEM /* defined */
198 #define CHIP_W1_BUS_START(v) 0x00000000UL
199 #define CHIP_W1_BUS_END(v) 0x00010000UL
200 #define CHIP_W1_SYS_START(v) 0x10030000UL
201 #define CHIP_W1_SYS_END(v) 0x10035000UL
202 #define CHIP_ACCESS_SIZE 1
203 #define CHIP_ALIGN_STRIDE 2
204
205 #include <mips/mips/bus_space_alignstride_chipdep.c>
206