1 /* $NetBSD: ar_conf.c,v 1.2 2011/07/10 06:26:02 matt Exp $ */ 2 /*- 3 * Copyright (c) 2011 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Matt Thomas of 3am Software Foundry. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 33 __KERNEL_RCSID(0, "$NetBSD: ar_conf.c,v 1.2 2011/07/10 06:26:02 matt Exp $"); 34 35 #include <sys/param.h> 36 37 #include "opt_wisoc.h" 38 39 #include <mips/cpuregs.h> 40 #include <mips/locore.h> 41 42 #include <mips/atheros/include/platform.h> 43 #include <mips/atheros/include/ar9344reg.h> 44 45 struct atheros_chip { 46 const struct atheros_platformsw *ac_platformsw; 47 const struct atheros_boardsw *ac_boardsw; 48 uint8_t ac_chipid; 49 uint8_t ac_chipmask; 50 uint8_t ac_cid; 51 uint8_t ac_pid; 52 const char ac_name[8]; 53 }; 54 55 static const struct atheros_chip chips[] = { 56 #ifdef WISOC_AR5312 57 { 58 .ac_platformsw = &ar5312_platformsw, 59 .ac_boardsw = &ar5312_boardsw, 60 .ac_chipid = ARCHIP_AR5312, 61 .ac_chipmask = 0xff, 62 .ac_cid = MIPS_PRID_CID_MTI, 63 .ac_pid = MIPS_4Kc, 64 .ac_name = "AR5312" 65 }, 66 #endif 67 #ifdef WISOC_AR5315 68 { 69 .ac_platformsw = &ar5315_platformsw, 70 .ac_boardsw = &ar5315_boardsw, 71 .ac_chipid = ARCHIP_AR5315, 72 .ac_chipmask = 0xf0, 73 .ac_cid = MIPS_PRID_CID_MTI, 74 .ac_pid = MIPS_4Kc, 75 .ac_name = "AR5315" 76 }, 77 #endif 78 #ifdef WISOC_AR7100 79 { 80 .ac_platformsw = &ar7100_platformsw, 81 .ac_chipid = ARCHIP_AR7130, 82 .ac_chipmask = 0xf3, 83 .ac_cid = MIPS_PRID_CID_MTI, 84 .ac_pid = MIPS_24K, 85 .ac_name = "AR7130" 86 }, { 87 .ac_platformsw = &ar7100_platformsw, 88 .ac_chipid = ARCHIP_AR7141, 89 .ac_chipmask = 0xf3, 90 .ac_cid = MIPS_PRID_CID_MTI, 91 .ac_pid = MIPS_24K, 92 .ac_name = "AR7141" 93 }, { 94 .ac_platformsw = &ar7100_platformsw, 95 .ac_chipid = ARCHIP_AR7161, 96 .ac_chipmask = 0xf3, 97 .ac_cid = MIPS_PRID_CID_MTI, 98 .ac_pid = MIPS_24K, 99 .ac_name = "AR7161" 100 }, 101 #endif 102 #ifdef WISOC_AR9344 103 { 104 .ac_platformsw = &ar9344_platformsw, 105 .ac_chipid = 0x20, /* 7240? */ 106 .ac_chipmask = 0xff, 107 .ac_cid = MIPS_PRID_CID_MTI, 108 .ac_pid = MIPS_74K, 109 .ac_name = "AR7240" 110 }, { 111 .ac_platformsw = &ar9344_platformsw, 112 .ac_chipid = ARCHIP_AR9344, 113 .ac_chipmask = 0xff, 114 .ac_cid = MIPS_PRID_CID_MTI, 115 .ac_pid = MIPS_74K, 116 .ac_name = "AR9344" 117 }, 118 #endif 119 }; 120 121 __CTASSERT(__arraycount(chips) > 0); 122 123 const struct atheros_platformsw *platformsw; 124 125 static const struct atheros_chip *my_chip; 126 127 static struct arfreqs chip_freqs; 128 129 const char * 130 atheros_get_cpuname(void) 131 { 132 return my_chip->ac_name; 133 } 134 135 u_int 136 atheros_get_chipid(void) 137 { 138 return my_chip->ac_chipid; 139 } 140 141 uint32_t 142 atheros_get_uart_freq(void) 143 { 144 if (chip_freqs.freq_uart) 145 return chip_freqs.freq_uart; 146 147 return chip_freqs.freq_bus; 148 } 149 150 uint32_t 151 atheros_get_bus_freq(void) 152 { 153 return chip_freqs.freq_bus; 154 } 155 156 uint32_t 157 atheros_get_cpu_freq(void) 158 { 159 return chip_freqs.freq_cpu; 160 } 161 162 uint32_t 163 atheros_get_mem_freq(void) 164 { 165 return chip_freqs.freq_mem; 166 } 167 168 void 169 atheros_set_platformsw(void) 170 { 171 const u_int cid = MIPS_PRID_CID(mips_options.mips_cpu_id); 172 const u_int pid = MIPS_PRID_IMPL(mips_options.mips_cpu_id); 173 174 for (const struct atheros_chip *ac = chips; 175 ac < chips + __arraycount(chips); 176 ac++) { 177 const struct atheros_platformsw * const apsw = ac->ac_platformsw; 178 if (cid != ac->ac_cid || pid != ac->ac_pid) 179 continue; 180 181 const uint32_t revision_id = *(volatile uint32_t *) 182 MIPS_PHYS_TO_KSEG1(apsw->apsw_revision_id_addr); 183 const uint32_t chipid = AR9344_REVISION_CHIPID(revision_id); 184 185 if ((chipid & ac->ac_chipmask) == ac->ac_chipid) { 186 platformsw = apsw; 187 my_chip = ac; 188 atheros_early_consinit(); 189 printf("Early console started!\n"); 190 (*apsw->apsw_get_freqs)(&chip_freqs); 191 printf("freqs: cpu=%u bus=%u mem=%u ref=%u pll=%u\n", 192 chip_freqs.freq_cpu, 193 chip_freqs.freq_bus, 194 chip_freqs.freq_mem, 195 chip_freqs.freq_ref, 196 chip_freqs.freq_pll); 197 return; 198 } 199 } 200 panic("%s: unrecognized platform", __func__); 201 } 202 203 #include "ath_arbus.h" 204 #if NATH_ARBUS > 0 205 #include <ah_soc.h> 206 207 const struct ar531x_boarddata * 208 atheros_get_board_info(void) 209 { 210 const struct atheros_boardsw * const boardsw = my_chip->ac_boardsw; 211 if (boardsw == NULL) 212 return NULL; 213 return (*boardsw->absw_get_board_info)(); 214 } 215 216 /* 217 * Locate board and radio configuration data in flash. 218 */ 219 int 220 atheros_get_board_config(struct ar531x_config *config) 221 { 222 const struct atheros_boardsw * const boardsw = my_chip->ac_boardsw; 223 if (boardsw == NULL) 224 return ENOENT; 225 226 config->board = (*boardsw->absw_get_board_info)(); 227 if (config->board == NULL) 228 return ENOENT; 229 230 config->radio = (*boardsw->absw_get_radio_info)(); 231 if (config->radio == NULL) 232 return ENOENT; /* XXX distinct code */ 233 234 return 0; 235 } 236 #endif /* NATH_ARBUS > 0 */ 237