3 * Description: Defines the platform resources for Gaia-based settops.
5 * Copyright (C) 2005-2009 Scientific-Atlanta, Inc.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 * NOTE: The bootloader allocates persistent memory at an address which is
22 * 16 MiB below the end of the highest address in KSEG0. All fixed
23 * address memory reservations must avoid this region.
26 #include <linux/device.h>
27 #include <linux/kernel.h>
28 #include <linux/init.h>
29 #include <linux/resource.h>
30 #include <linux/serial_reg.h>
32 #include <linux/bootmem.h>
34 #include <linux/platform_device.h>
35 #include <linux/module.h>
37 #include <linux/swap.h>
38 #include <linux/highmem.h>
39 #include <linux/dma-mapping.h>
41 #include <asm/mach-powertv/asic.h>
42 #include <asm/mach-powertv/asic_regs.h>
43 #include <asm/mach-powertv/interrupts.h>
45 #ifdef CONFIG_BOOTLOADER_DRIVER
46 #include <asm/mach-powertv/kbldr.h>
48 #include <asm/bootinfo.h>
50 #define BOOTLDRFAMILY(byte1, byte0) (((byte1) << 8) | (byte0))
55 static void pmem_setup_resource(void);
62 unsigned int platform_features
;
63 unsigned int platform_family
;
64 struct register_map _asic_register_map
;
65 EXPORT_SYMBOL(_asic_register_map
); /* Exported for testing */
66 unsigned long asic_phy_base
;
67 unsigned long asic_base
;
68 EXPORT_SYMBOL(asic_base
); /* Exported for testing */
69 struct resource
*gp_resources
;
72 * Don't recommend to use it directly, it is usually used by kernel internally.
73 * Portable code should be using interfaces such as ioremp, dma_map_single, etc.
75 unsigned long phys_to_dma_offset
;
76 EXPORT_SYMBOL(phys_to_dma_offset
);
80 * IO Resource Definition
84 struct resource asic_resource
= {
85 .name
= "ASIC Resource",
88 .flags
= IORESOURCE_MEM
,
92 * Allow override of bootloader-specified model
93 * Returns zero on success, a negative errno value on failure. This parameter
94 * allows overriding of the bootloader-specified model.
96 static char __initdata cmdline
[COMMAND_LINE_SIZE
];
98 #define FORCEFAMILY_PARAM "forcefamily"
101 * check_forcefamily - check for, and parse, forcefamily command line parameter
102 * @forced_family: Pointer to two-character array in which to store the
103 * value of the forcedfamily parameter, if any.
105 static __init
int check_forcefamily(unsigned char forced_family
[2])
109 forced_family
[0] = '\0';
110 forced_family
[1] = '\0';
112 /* Check the command line for a forcefamily directive */
113 strncpy(cmdline
, arcs_cmdline
, COMMAND_LINE_SIZE
- 1);
114 p
= strstr(cmdline
, FORCEFAMILY_PARAM
);
115 if (p
&& (p
!= cmdline
) && (*(p
- 1) != ' '))
116 p
= strstr(p
, " " FORCEFAMILY_PARAM
"=");
119 p
+= strlen(FORCEFAMILY_PARAM
"=");
121 if (*p
== '\0' || *(p
+ 1) == '\0' ||
122 (*(p
+ 2) != '\0' && *(p
+ 2) != ' '))
123 pr_err(FORCEFAMILY_PARAM
" must be exactly two "
124 "characters long, ignoring value\n");
127 forced_family
[0] = *p
;
128 forced_family
[1] = *(p
+ 1);
136 * platform_set_family - determine major platform family type.
138 * Returns family type; -1 if none
139 * Returns the family type; -1 if none
142 static __init noinline
void platform_set_family(void)
144 unsigned char forced_family
[2];
145 unsigned short bootldr_family
;
147 if (check_forcefamily(forced_family
) == 0)
148 bootldr_family
= BOOTLDRFAMILY(forced_family
[0],
152 #ifdef CONFIG_BOOTLOADER_DRIVER
153 bootldr_family
= (unsigned short) kbldr_GetSWFamily();
155 #if defined(CONFIG_BOOTLOADER_FAMILY)
156 bootldr_family
= (unsigned short) BOOTLDRFAMILY(
157 CONFIG_BOOTLOADER_FAMILY
[0],
158 CONFIG_BOOTLOADER_FAMILY
[1]);
160 #error "Unknown Bootloader Family"
165 pr_info("Bootloader Family = 0x%04X\n", bootldr_family
);
167 switch (bootldr_family
) {
168 case BOOTLDRFAMILY('R', '1'):
169 platform_family
= FAMILY_1500
;
171 case BOOTLDRFAMILY('4', '4'):
172 platform_family
= FAMILY_4500
;
174 case BOOTLDRFAMILY('4', '6'):
175 platform_family
= FAMILY_4600
;
177 case BOOTLDRFAMILY('A', '1'):
178 platform_family
= FAMILY_4600VZA
;
180 case BOOTLDRFAMILY('8', '5'):
181 platform_family
= FAMILY_8500
;
183 case BOOTLDRFAMILY('R', '2'):
184 platform_family
= FAMILY_8500RNG
;
186 case BOOTLDRFAMILY('8', '6'):
187 platform_family
= FAMILY_8600
;
189 case BOOTLDRFAMILY('B', '1'):
190 platform_family
= FAMILY_8600VZB
;
192 case BOOTLDRFAMILY('E', '1'):
193 platform_family
= FAMILY_1500VZE
;
195 case BOOTLDRFAMILY('F', '1'):
196 platform_family
= FAMILY_1500VZF
;
198 case BOOTLDRFAMILY('8', '7'):
199 platform_family
= FAMILY_8700
;
202 platform_family
= -1;
206 unsigned int platform_get_family(void)
208 return platform_family
;
210 EXPORT_SYMBOL(platform_get_family
);
213 * platform_get_asic - determine the ASIC type.
215 * Returns the ASIC type, or ASIC_UNKNOWN if unknown
218 enum asic_type
platform_get_asic(void)
222 EXPORT_SYMBOL(platform_get_asic
);
225 * set_register_map - set ASIC register configuration
226 * @phys_base: Physical address of the base of the ASIC registers
227 * @map: Description of key ASIC registers
229 static void __init
set_register_map(unsigned long phys_base
,
230 const struct register_map
*map
)
232 asic_phy_base
= phys_base
;
233 _asic_register_map
= *map
;
234 register_map_virtualize(&_asic_register_map
);
235 asic_base
= (unsigned long)ioremap_nocache(phys_base
, ASIC_IO_SIZE
);
239 * configure_platform - configuration based on platform type.
241 void __init
configure_platform(void)
243 platform_set_family();
245 switch (platform_family
) {
249 platform_features
= FFS_CAPABLE
;
250 asic
= ASIC_CALLIOPE
;
251 set_register_map(CALLIOPE_IO_BASE
, &calliope_register_map
);
253 if (platform_family
== FAMILY_1500VZE
) {
254 gp_resources
= non_dvr_vze_calliope_resources
;
255 pr_info("Platform: 1500/Vz Class E - "
256 "CALLIOPE, NON_DVR_CAPABLE\n");
257 } else if (platform_family
== FAMILY_1500VZF
) {
258 gp_resources
= non_dvr_vzf_calliope_resources
;
259 pr_info("Platform: 1500/Vz Class F - "
260 "CALLIOPE, NON_DVR_CAPABLE\n");
262 gp_resources
= non_dvr_calliope_resources
;
263 pr_info("Platform: 1500/RNG100 - CALLIOPE, "
264 "NON_DVR_CAPABLE\n");
269 platform_features
= FFS_CAPABLE
| PCIE_CAPABLE
|
272 set_register_map(ZEUS_IO_BASE
, &zeus_register_map
);
273 gp_resources
= non_dvr_zeus_resources
;
275 pr_info("Platform: 4500 - ZEUS, NON_DVR_CAPABLE\n");
280 unsigned int chipversion
= 0;
282 /* The settop has PCIE but it isn't used, so don't advertise
284 platform_features
= FFS_CAPABLE
| DISPLAY_CAPABLE
;
286 /* Cronus and Cronus Lite have the same register map */
287 set_register_map(CRONUS_IO_BASE
, &cronus_register_map
);
289 /* ASIC version will determine if this is a real CronusLite or
290 * Castrati(Cronus) */
291 chipversion
= asic_read(chipver3
) << 24;
292 chipversion
|= asic_read(chipver2
) << 16;
293 chipversion
|= asic_read(chipver1
) << 8;
294 chipversion
|= asic_read(chipver0
);
296 if ((chipversion
== CRONUS_10
) || (chipversion
== CRONUS_11
))
299 asic
= ASIC_CRONUSLITE
;
301 gp_resources
= non_dvr_cronuslite_resources
;
302 pr_info("Platform: 4600 - %s, NON_DVR_CAPABLE, "
303 "chipversion=0x%08X\n",
304 (asic
== ASIC_CRONUS
) ? "CRONUS" : "CRONUS LITE",
309 platform_features
= FFS_CAPABLE
| DISPLAY_CAPABLE
;
311 set_register_map(CRONUS_IO_BASE
, &cronus_register_map
);
312 gp_resources
= non_dvr_cronus_resources
;
314 pr_info("Platform: Vz Class A - CRONUS, NON_DVR_CAPABLE\n");
319 platform_features
= DVR_CAPABLE
| PCIE_CAPABLE
|
322 set_register_map(ZEUS_IO_BASE
, &zeus_register_map
);
323 gp_resources
= dvr_zeus_resources
;
325 pr_info("Platform: 8500/RNG200 - ZEUS, DVR_CAPABLE\n");
330 platform_features
= DVR_CAPABLE
| PCIE_CAPABLE
|
333 set_register_map(CRONUS_IO_BASE
, &cronus_register_map
);
334 gp_resources
= dvr_cronus_resources
;
336 pr_info("Platform: 8600/Vz Class B - CRONUS, "
341 platform_features
= FFS_CAPABLE
| PCIE_CAPABLE
;
343 set_register_map(GAIA_IO_BASE
, &gaia_register_map
);
344 gp_resources
= dvr_gaia_resources
;
346 pr_info("Platform: 8700 - GAIA, DVR_CAPABLE\n");
350 pr_crit("Platform: UNKNOWN PLATFORM\n");
356 phys_to_dma_offset
= 0x30000000;
359 phys_to_dma_offset
= 0x10000000;
361 case ASIC_CRONUSLITE
:
365 * TODO: We suppose 0x10000000 aliases into 0x20000000-
366 * 0x2XXXXXXX. If 0x10000000 aliases into 0x60000000-
367 * 0x6XXXXXXX, the offset should be 0x50000000, not 0x10000000.
369 phys_to_dma_offset
= 0x10000000;
372 phys_to_dma_offset
= 0x00000000;
378 * RESOURCE ALLOCATION
382 * Allocates/reserves the Platform memory resources early in the boot process.
383 * This ignores any resources that are designated IORESOURCE_IO
385 void __init
platform_alloc_bootmem(void)
390 /* Get persistent memory data from command line before allocating
391 * resources. This need to happen before normal command line parsing
393 pmem_setup_resource();
395 /* Loop through looking for resources that want a particular address */
396 for (i
= 0; gp_resources
[i
].flags
!= 0; i
++) {
397 int size
= resource_size(&gp_resources
[i
]);
398 if ((gp_resources
[i
].start
!= 0) &&
399 ((gp_resources
[i
].flags
& IORESOURCE_MEM
) != 0)) {
400 reserve_bootmem(dma_to_phys(gp_resources
[i
].start
),
402 total
+= resource_size(&gp_resources
[i
]);
403 pr_info("reserve resource %s at %08x (%u bytes)\n",
404 gp_resources
[i
].name
, gp_resources
[i
].start
,
405 resource_size(&gp_resources
[i
]));
409 /* Loop through assigning addresses for those that are left */
410 for (i
= 0; gp_resources
[i
].flags
!= 0; i
++) {
411 int size
= resource_size(&gp_resources
[i
]);
412 if ((gp_resources
[i
].start
== 0) &&
413 ((gp_resources
[i
].flags
& IORESOURCE_MEM
) != 0)) {
414 void *mem
= alloc_bootmem_pages(size
);
417 pr_err("Unable to allocate bootmem pages "
418 "for %s\n", gp_resources
[i
].name
);
421 gp_resources
[i
].start
=
422 phys_to_dma(virt_to_phys(mem
));
423 gp_resources
[i
].end
=
424 gp_resources
[i
].start
+ size
- 1;
426 pr_info("allocate resource %s at %08x "
428 gp_resources
[i
].name
,
429 gp_resources
[i
].start
, size
);
434 pr_info("Total Platform driver memory allocation: 0x%08x\n", total
);
436 /* indicate resources that are platform I/O related */
437 for (i
= 0; gp_resources
[i
].flags
!= 0; i
++) {
438 if ((gp_resources
[i
].start
!= 0) &&
439 ((gp_resources
[i
].flags
& IORESOURCE_IO
) != 0)) {
440 pr_info("reserved platform resource %s at %08x\n",
441 gp_resources
[i
].name
, gp_resources
[i
].start
);
448 * PERSISTENT MEMORY (PMEM) CONFIGURATION
451 static unsigned long pmemaddr __initdata
;
453 static int __init
early_param_pmemaddr(char *p
)
455 pmemaddr
= (unsigned long)simple_strtoul(p
, NULL
, 0);
458 early_param("pmemaddr", early_param_pmemaddr
);
460 static long pmemlen __initdata
;
462 static int __init
early_param_pmemlen(char *p
)
464 /* TODO: we can use this code when and if the bootloader ever changes this */
466 pmemlen
= (unsigned long)simple_strtoul(p
, NULL
, 0);
472 early_param("pmemlen", early_param_pmemlen
);
475 * Set up persistent memory. If we were given values, we patch the array of
476 * resources. Otherwise, persistent memory may be allocated anywhere at all.
478 static void __init
pmem_setup_resource(void)
480 struct resource
*resource
;
481 resource
= asic_resource_get("DiagPersistentMemory");
483 if (resource
&& pmemaddr
&& pmemlen
) {
484 /* The address provided by bootloader is in kseg0. Convert to
486 resource
->start
= phys_to_dma(pmemaddr
- 0x80000000);
487 resource
->end
= resource
->start
+ pmemlen
- 1;
489 pr_info("persistent memory: start=0x%x end=0x%x\n",
490 resource
->start
, resource
->end
);
496 * RESOURCE ACCESS FUNCTIONS
501 * asic_resource_get - retrieves parameters for a platform resource.
502 * @name: string to match resource
504 * Returns a pointer to a struct resource corresponding to the given name.
506 * CANNOT BE NAMED platform_resource_get, which would be the obvious choice,
507 * as this function name is already declared
509 struct resource
*asic_resource_get(const char *name
)
513 for (i
= 0; gp_resources
[i
].flags
!= 0; i
++) {
514 if (strcmp(gp_resources
[i
].name
, name
) == 0)
515 return &gp_resources
[i
];
520 EXPORT_SYMBOL(asic_resource_get
);
523 * platform_release_memory - release pre-allocated memory
524 * @ptr: pointer to memory to release
525 * @size: size of resource
527 * This must only be called for memory allocated or reserved via the boot
530 void platform_release_memory(void *ptr
, int size
)
535 addr
= ((unsigned long)ptr
+ (PAGE_SIZE
- 1)) & PAGE_MASK
;
536 end
= ((unsigned long)ptr
+ size
) & PAGE_MASK
;
538 for (; addr
< end
; addr
+= PAGE_SIZE
) {
539 ClearPageReserved(virt_to_page(__va(addr
)));
540 init_page_count(virt_to_page(__va(addr
)));
541 free_page((unsigned long)__va(addr
));
544 EXPORT_SYMBOL(platform_release_memory
);
548 * FEATURE AVAILABILITY FUNCTIONS
551 int platform_supports_dvr(void)
553 return (platform_features
& DVR_CAPABLE
) != 0;
556 int platform_supports_ffs(void)
558 return (platform_features
& FFS_CAPABLE
) != 0;
561 int platform_supports_pcie(void)
563 return (platform_features
& PCIE_CAPABLE
) != 0;
566 int platform_supports_display(void)
568 return (platform_features
& DISPLAY_CAPABLE
) != 0;