1 /*-
2 * Copyright (c) 2017, Adrian Chadd <adrian@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 unmodified, this list of conditions, and the following
10 * disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/cdefs.h>
29 #include "opt_ar71xx.h"
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33
34 #include <sys/bus.h>
35 #include <sys/interrupt.h>
36 #include <sys/malloc.h>
37 #include <sys/kernel.h>
38 #include <sys/module.h>
39 #include <sys/rman.h>
40 #include <sys/lock.h>
41
42 #include <vm/vm.h>
43 #include <vm/pmap.h>
44 #include <vm/vm_extern.h>
45
46 #include <machine/bus.h>
47 #include <machine/cpu.h>
48 #include <machine/intr_machdep.h>
49
50 #include <sys/linker.h>
51 #include <sys/firmware.h>
52
53 struct ar71xx_caldata_softc {
54 device_t sc_dev;
55 };
56
57 static int
ar71xx_caldata_probe(device_t dev)58 ar71xx_caldata_probe(device_t dev)
59 {
60
61 return (BUS_PROBE_NOWILDCARD);
62 }
63
64 /* XXX TODO: unify with what's in ar71xx_fixup.c */
65
66 /*
67 * Create a calibration block from memory mapped SPI data for use by
68 * various drivers. Right now it's just ath(4) but later board support
69 * will include 802.11ac NICs with calibration data in NOR flash.
70 *
71 * (Yes, there are a handful of QCA MIPS boards with QCA9880v2 802.11ac chips
72 * with calibration data in flash..)
73 */
74 static void
ar71xx_platform_create_cal_data(device_t dev,int id,long int flash_addr,int size)75 ar71xx_platform_create_cal_data(device_t dev, int id, long int flash_addr,
76 int size)
77 {
78 char buf[64];
79 uint16_t *cal_data = (uint16_t *) MIPS_PHYS_TO_KSEG1(flash_addr);
80 void *eeprom = NULL;
81 const struct firmware *fw = NULL;
82
83 device_printf(dev, "EEPROM firmware: 0x%lx @ %d bytes\n",
84 flash_addr, size);
85
86 eeprom = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
87 if (! eeprom) {
88 device_printf(dev, "%s: malloc failed for '%s', aborting EEPROM\n",
89 __func__, buf);
90 return;
91 }
92
93 memcpy(eeprom, cal_data, size);
94
95 /*
96 * Generate a flash EEPROM 'firmware' from the given memory
97 * region. Since the SPI controller will eventually
98 * go into port-IO mode instead of memory-mapped IO
99 * mode, a copy of the EEPROM contents is required.
100 */
101
102 snprintf(buf, sizeof(buf), "%s.%d.map.%d.eeprom_firmware",
103 device_get_name(dev),
104 device_get_unit(dev),
105 id);
106
107 fw = firmware_register(buf, eeprom, size, 1, NULL);
108 if (fw == NULL) {
109 device_printf(dev, "%s: firmware_register (%s) failed\n",
110 __func__, buf);
111 free(eeprom, M_DEVBUF);
112 return;
113 }
114 device_printf(dev, "device EEPROM '%s' registered\n", buf);
115 }
116
117 /*
118 * Iterate through a list of early-boot hints creating calibration
119 * data firmware chunks for AHB (ie, non-PCI) devices with calibration
120 * data.
121 */
122 static int
ar71xx_platform_check_eeprom_hints(device_t dev)123 ar71xx_platform_check_eeprom_hints(device_t dev)
124 {
125 char buf[64];
126 long int addr;
127 int size;
128 int i;
129
130 for (i = 0; i < 8; i++) {
131 snprintf(buf, sizeof(buf), "map.%d.ath_fixup_addr", i);
132 if (resource_long_value(device_get_name(dev),
133 device_get_unit(dev), buf, &addr) != 0)
134 break;
135 snprintf(buf, sizeof(buf), "map.%d.ath_fixup_size", i);
136 if (resource_int_value(device_get_name(dev),
137 device_get_unit(dev), buf, &size) != 0)
138 break;
139 device_printf(dev, "map.%d.ath_fixup_addr=0x%08x; size=%d\n",
140 i, (int) addr, size);
141 (void) ar71xx_platform_create_cal_data(dev, i, addr, size);
142 }
143
144 return (0);
145 }
146
147 static int
ar71xx_caldata_attach(device_t dev)148 ar71xx_caldata_attach(device_t dev)
149 {
150
151 device_add_child(dev, "nexus", -1);
152 ar71xx_platform_check_eeprom_hints(dev);
153 return (bus_generic_attach(dev));
154 }
155
156 static device_method_t ar71xx_caldata_methods[] = {
157 /* Device interface */
158 DEVMETHOD(device_probe, ar71xx_caldata_probe),
159 DEVMETHOD(device_attach, ar71xx_caldata_attach),
160 DEVMETHOD(device_shutdown, bus_generic_shutdown),
161 DEVMETHOD(device_suspend, bus_generic_suspend),
162 DEVMETHOD(device_resume, bus_generic_resume),
163 DEVMETHOD_END
164 };
165
166 static driver_t ar71xx_caldata_driver = {
167 "ar71xx_caldata",
168 ar71xx_caldata_methods,
169 sizeof(struct ar71xx_caldata_softc),
170 };
171
172 static devclass_t ar71xx_caldata_devclass;
173
174 DRIVER_MODULE(ar71xx_caldata, nexus, ar71xx_caldata_driver, ar71xx_caldata_devclass, 0, 0);
175