xref: /freebsd/sys/arm/freescale/imx/imx6_machdep.c (revision f02f7422801bb39f5eaab8fc383fa7b70c467ff9)
1 /*-
2  * Copyright (c) 2013 Ian Lepore <ian@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include "opt_platform.h"
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35 #include <sys/reboot.h>
36 
37 #include <vm/vm.h>
38 
39 #include <machine/bus.h>
40 #include <machine/devmap.h>
41 #include <machine/intr.h>
42 #include <machine/machdep.h>
43 #include <machine/platform.h>
44 
45 #include <arm/arm/mpcore_timervar.h>
46 #include <arm/freescale/imx/imx6_anatopreg.h>
47 #include <arm/freescale/imx/imx6_anatopvar.h>
48 #include <arm/freescale/imx/imx_machdep.h>
49 
50 #include <dev/fdt/fdt_common.h>
51 #include <dev/ofw/openfirm.h>
52 
53 struct fdt_fixup_entry fdt_fixup_table[] = {
54 	{ NULL, NULL }
55 };
56 
57 fdt_pic_decode_t fdt_pic_table[] = {
58 	&gic_decode_fdt,
59 	NULL
60 };
61 
62 vm_offset_t
63 platform_lastaddr(void)
64 {
65 
66 	return (arm_devmap_lastaddr());
67 }
68 
69 void
70 platform_probe_and_attach(void)
71 {
72 
73 	/* Inform the MPCore timer driver that its clock is variable. */
74 	arm_tmr_change_frequency(ARM_TMR_FREQUENCY_VARIES);
75 }
76 
77 void
78 platform_gpio_init(void)
79 {
80 
81 }
82 
83 void
84 platform_late_init(void)
85 {
86 
87 }
88 
89 /*
90  * Set up static device mappings.
91  *
92  * This attempts to cover the most-used devices with 1MB section mappings, which
93  * is good for performance (uses fewer TLB entries for device access).
94  *
95  * ARMMP covers the interrupt controller, MPCore timers, global timer, and the
96  * L2 cache controller.  Most of the 1MB range is unused reserved space.
97  *
98  * AIPS1/AIPS2 cover most of the on-chip devices such as uart, spi, i2c, etc.
99  *
100  * Notably not mapped right now are HDMI, GPU, and other devices below ARMMP in
101  * the memory map.  When we get support for graphics it might make sense to
102  * static map some of that area.  Be careful with other things in that area such
103  * as OCRAM that probably shouldn't be mapped as PTE_DEVICE memory.
104  */
105 int
106 platform_devmap_init(void)
107 {
108 	const uint32_t IMX6_ARMMP_PHYS = 0x00a00000;
109 	const uint32_t IMX6_ARMMP_SIZE = 0x00100000;
110 	const uint32_t IMX6_AIPS1_PHYS = 0x02000000;
111 	const uint32_t IMX6_AIPS1_SIZE = 0x00100000;
112 	const uint32_t IMX6_AIPS2_PHYS = 0x02100000;
113 	const uint32_t IMX6_AIPS2_SIZE = 0x00100000;
114 
115 	arm_devmap_add_entry(IMX6_ARMMP_PHYS, IMX6_ARMMP_SIZE);
116 	arm_devmap_add_entry(IMX6_AIPS1_PHYS, IMX6_AIPS1_SIZE);
117 	arm_devmap_add_entry(IMX6_AIPS2_PHYS, IMX6_AIPS2_SIZE);
118 
119 	return (0);
120 }
121 
122 void
123 cpu_reset(void)
124 {
125 	const uint32_t IMX6_WDOG_CR_PHYS = 0x020bc000;
126 
127 	imx_wdog_cpu_reset(IMX6_WDOG_CR_PHYS);
128 }
129 
130 /*
131  * Determine what flavor of imx6 we're running on.
132  *
133  * This code is based on the way u-boot does it.  Information found on the web
134  * indicates that Freescale themselves were the original source of this logic,
135  * including the strange check for number of CPUs in the SCU configuration
136  * register, which is apparently needed on some revisions of the SOLO.
137  *
138  * According to the documentation, there is such a thing as an i.MX6 Dual
139  * (non-lite flavor).  However, Freescale doesn't seem to have assigned it a
140  * number or provided any logic to handle it in their detection code.
141  *
142  * Note that the ANALOG_DIGPROG and SCU configuration registers are not
143  * documented in the chip reference manual.  (SCU configuration is mentioned,
144  * but not mapped out in detail.)  I think the bottom two bits of the scu config
145  * register may be ncpu-1.
146  *
147  * This hasn't been tested yet on a dual[-lite].
148  *
149  * On a solo:
150  *      digprog    = 0x00610001
151  *      hwsoc      = 0x00000062
152  *      scu config = 0x00000500
153  * On a quad:
154  *      digprog    = 0x00630002
155  *      hwsoc      = 0x00000063
156  *      scu config = 0x00005503
157  */
158 u_int imx_soc_type()
159 {
160 	uint32_t digprog, hwsoc;
161 	uint32_t *pcr;
162 	static u_int soctype;
163 	const vm_offset_t SCU_CONFIG_PHYSADDR = 0x00a00004;
164 #define	HWSOC_MX6SL	0x60
165 #define	HWSOC_MX6DL	0x61
166 #define	HWSOC_MX6SOLO	0x62
167 #define	HWSOC_MX6Q	0x63
168 
169 	if (soctype != 0)
170 		return (soctype);
171 
172 	digprog = imx6_anatop_read_4(IMX6_ANALOG_DIGPROG_SL);
173 	hwsoc = (digprog >> IMX6_ANALOG_DIGPROG_SOCTYPE_SHIFT) &
174 	    IMX6_ANALOG_DIGPROG_SOCTYPE_MASK;
175 
176 	if (hwsoc != HWSOC_MX6SL) {
177 		digprog = imx6_anatop_read_4(IMX6_ANALOG_DIGPROG);
178 		hwsoc = (digprog & IMX6_ANALOG_DIGPROG_SOCTYPE_MASK) >>
179 		    IMX6_ANALOG_DIGPROG_SOCTYPE_SHIFT;
180 		/*printf("digprog = 0x%08x\n", digprog);*/
181 		if (hwsoc == HWSOC_MX6DL) {
182 			pcr = arm_devmap_ptov(SCU_CONFIG_PHYSADDR, 4);
183 			if (pcr != NULL) {
184 				/*printf("scu config = 0x%08x\n", *pcr);*/
185 				if ((*pcr & 0x03) == 0) {
186 					hwsoc = HWSOC_MX6SOLO;
187 				}
188 			}
189 		}
190 	}
191 	/* printf("hwsoc 0x%08x\n", hwsoc); */
192 
193 	switch (hwsoc) {
194 	case HWSOC_MX6SL:
195 		soctype = IMXSOC_6SL;
196 		break;
197 	case HWSOC_MX6SOLO:
198 		soctype = IMXSOC_6S;
199 		break;
200 	case HWSOC_MX6DL:
201 		soctype = IMXSOC_6DL;
202 		break;
203 	case HWSOC_MX6Q :
204 		soctype = IMXSOC_6Q;
205 		break;
206 	default:
207 		printf("imx_soc_type: Don't understand hwsoc 0x%02x, "
208 		    "digprog 0x%08x; assuming IMXSOC_6Q\n", hwsoc, digprog);
209 		soctype = IMXSOC_6Q;
210 		break;
211 	}
212 
213 	return (soctype);
214 }
215 
216 /*
217  * Early putc routine for EARLY_PRINTF support.  To use, add to kernel config:
218  *   option SOCDEV_PA=0x02000000
219  *   option SOCDEV_VA=0x02000000
220  *   option EARLY_PRINTF
221  * Resist the temptation to change the #if 0 to #ifdef EARLY_PRINTF here. It
222  * makes sense now, but if multiple SOCs do that it will make early_putc another
223  * duplicate symbol to be eliminated on the path to a generic kernel.
224  */
225 #if 0
226 static void
227 imx6_early_putc(int c)
228 {
229 	volatile uint32_t * UART_STAT_REG = (uint32_t *)0x02020098;
230 	volatile uint32_t * UART_TX_REG   = (uint32_t *)0x02020040;
231 	const uint32_t      UART_TXRDY    = (1 << 3);
232 
233 	while ((*UART_STAT_REG & UART_TXRDY) == 0)
234 		continue;
235 	*UART_TX_REG = c;
236 }
237 early_putc_t *early_putc = imx6_early_putc;
238 #endif
239 
240