xref: /freebsd/sys/arm/freescale/imx/imx6_machdep.c (revision 0572ccaa4543b0abef8ef81e384c1d04de9f3da1)
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/machdep.h>
42 #include <machine/platform.h>
43 
44 #include <arm/arm/mpcore_timervar.h>
45 #include <arm/freescale/imx/imx6_anatopreg.h>
46 #include <arm/freescale/imx/imx6_anatopvar.h>
47 #include <arm/freescale/imx/imx_machdep.h>
48 
49 vm_offset_t
50 platform_lastaddr(void)
51 {
52 
53 	return (arm_devmap_lastaddr());
54 }
55 
56 void
57 platform_probe_and_attach(void)
58 {
59 
60 	/* Inform the MPCore timer driver that its clock is variable. */
61 	arm_tmr_change_frequency(ARM_TMR_FREQUENCY_VARIES);
62 }
63 
64 void
65 platform_gpio_init(void)
66 {
67 
68 }
69 
70 void
71 platform_late_init(void)
72 {
73 
74 }
75 
76 /*
77  * Set up static device mappings.
78  *
79  * This attempts to cover the most-used devices with 1MB section mappings, which
80  * is good for performance (uses fewer TLB entries for device access).
81  *
82  * ARMMP covers the interrupt controller, MPCore timers, global timer, and the
83  * L2 cache controller.  Most of the 1MB range is unused reserved space.
84  *
85  * AIPS1/AIPS2 cover most of the on-chip devices such as uart, spi, i2c, etc.
86  *
87  * Notably not mapped right now are HDMI, GPU, and other devices below ARMMP in
88  * the memory map.  When we get support for graphics it might make sense to
89  * static map some of that area.  Be careful with other things in that area such
90  * as OCRAM that probably shouldn't be mapped as PTE_DEVICE memory.
91  */
92 int
93 platform_devmap_init(void)
94 {
95 	const uint32_t IMX6_ARMMP_PHYS = 0x00a00000;
96 	const uint32_t IMX6_ARMMP_SIZE = 0x00100000;
97 	const uint32_t IMX6_AIPS1_PHYS = 0x02000000;
98 	const uint32_t IMX6_AIPS1_SIZE = 0x00100000;
99 	const uint32_t IMX6_AIPS2_PHYS = 0x02100000;
100 	const uint32_t IMX6_AIPS2_SIZE = 0x00100000;
101 
102 	arm_devmap_add_entry(IMX6_ARMMP_PHYS, IMX6_ARMMP_SIZE);
103 	arm_devmap_add_entry(IMX6_AIPS1_PHYS, IMX6_AIPS1_SIZE);
104 	arm_devmap_add_entry(IMX6_AIPS2_PHYS, IMX6_AIPS2_SIZE);
105 
106 	return (0);
107 }
108 
109 void
110 cpu_reset(void)
111 {
112 	const uint32_t IMX6_WDOG_CR_PHYS = 0x020bc000;
113 
114 	imx_wdog_cpu_reset(IMX6_WDOG_CR_PHYS);
115 }
116 
117 /*
118  * Determine what flavor of imx6 we're running on.
119  *
120  * This code is based on the way u-boot does it.  Information found on the web
121  * indicates that Freescale themselves were the original source of this logic,
122  * including the strange check for number of CPUs in the SCU configuration
123  * register, which is apparently needed on some revisions of the SOLO.
124  *
125  * According to the documentation, there is such a thing as an i.MX6 Dual
126  * (non-lite flavor).  However, Freescale doesn't seem to have assigned it a
127  * number or provided any logic to handle it in their detection code.
128  *
129  * Note that the ANALOG_DIGPROG and SCU configuration registers are not
130  * documented in the chip reference manual.  (SCU configuration is mentioned,
131  * but not mapped out in detail.)  I think the bottom two bits of the scu config
132  * register may be ncpu-1.
133  *
134  * This hasn't been tested yet on a dual[-lite].
135  *
136  * On a solo:
137  *      digprog    = 0x00610001
138  *      hwsoc      = 0x00000062
139  *      scu config = 0x00000500
140  * On a quad:
141  *      digprog    = 0x00630002
142  *      hwsoc      = 0x00000063
143  *      scu config = 0x00005503
144  */
145 u_int imx_soc_type()
146 {
147 	uint32_t digprog, hwsoc;
148 	uint32_t *pcr;
149 	const vm_offset_t SCU_CONFIG_PHYSADDR = 0x00a00004;
150 #define	HWSOC_MX6SL	0x60
151 #define	HWSOC_MX6DL	0x61
152 #define	HWSOC_MX6SOLO	0x62
153 #define	HWSOC_MX6Q	0x63
154 
155 	digprog = imx6_anatop_read_4(IMX6_ANALOG_DIGPROG_SL);
156 	hwsoc = (digprog >> IMX6_ANALOG_DIGPROG_SOCTYPE_SHIFT) &
157 	    IMX6_ANALOG_DIGPROG_SOCTYPE_MASK;
158 
159 	if (hwsoc != HWSOC_MX6SL) {
160 		digprog = imx6_anatop_read_4(IMX6_ANALOG_DIGPROG);
161 		hwsoc = (digprog & IMX6_ANALOG_DIGPROG_SOCTYPE_MASK) >>
162 		    IMX6_ANALOG_DIGPROG_SOCTYPE_SHIFT;
163 		/*printf("digprog = 0x%08x\n", digprog);*/
164 		if (hwsoc == HWSOC_MX6DL) {
165 			pcr = arm_devmap_ptov(SCU_CONFIG_PHYSADDR, 4);
166 			if (pcr != NULL) {
167 				/*printf("scu config = 0x%08x\n", *pcr);*/
168 				if ((*pcr & 0x03) == 0) {
169 					hwsoc = HWSOC_MX6SOLO;
170 				}
171 			}
172 		}
173 	}
174 	/* printf("hwsoc 0x%08x\n", hwsoc); */
175 
176 	switch (hwsoc) {
177 	case HWSOC_MX6SL:
178 		return (IMXSOC_6SL);
179 	case HWSOC_MX6SOLO:
180 		return (IMXSOC_6S);
181 	case HWSOC_MX6DL:
182 		return (IMXSOC_6DL);
183 	case HWSOC_MX6Q :
184 		return (IMXSOC_6Q);
185 	default:
186 		printf("imx_soc_type: Don't understand hwsoc 0x%02x, "
187 		    "digprog 0x%08x; assuming IMXSOC_6Q\n", hwsoc, digprog);
188 		break;
189 	}
190 
191 	return (IMXSOC_6Q);
192 }
193 
194 /*
195  * Early putc routine for EARLY_PRINTF support.  To use, add to kernel config:
196  *   option SOCDEV_PA=0x02000000
197  *   option SOCDEV_VA=0x02000000
198  *   option EARLY_PRINTF
199  * Resist the temptation to change the #if 0 to #ifdef EARLY_PRINTF here. It
200  * makes sense now, but if multiple SOCs do that it will make early_putc another
201  * duplicate symbol to be eliminated on the path to a generic kernel.
202  */
203 #if 0
204 static void
205 imx6_early_putc(int c)
206 {
207 	volatile uint32_t * UART_STAT_REG = (uint32_t *)0x02020098;
208 	volatile uint32_t * UART_TX_REG   = (uint32_t *)0x02020040;
209 	const uint32_t      UART_TXRDY    = (1 << 3);
210 
211 	while ((*UART_STAT_REG & UART_TXRDY) == 0)
212 		continue;
213 	*UART_TX_REG = c;
214 }
215 early_putc_t *early_putc = imx6_early_putc;
216 #endif
217 
218