2 * ASIC Device List Intialization
4 * Description: Defines the platform resources for the SA settop.
6 * Copyright (C) 2005-2009 Scientific-Atlanta, Inc.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * Author: Ken Eppinett
23 * David Schleef <ds@schleef.org>
25 * Description: Defines the platform resources for the SA settop.
27 * NOTE: The bootloader allocates persistent memory at an address which is
28 * 16 MiB below the end of the highest address in KSEG0. All fixed
29 * address memory reservations must avoid this region.
32 #include <linux/device.h>
33 #include <linux/kernel.h>
34 #include <linux/init.h>
35 #include <linux/resource.h>
36 #include <linux/serial_reg.h>
38 #include <linux/bootmem.h>
40 #include <linux/platform_device.h>
41 #include <linux/module.h>
42 #include <linux/gfp.h>
44 #include <linux/swap.h>
45 #include <linux/highmem.h>
46 #include <linux/dma-mapping.h>
48 #include <asm/mach-powertv/asic.h>
49 #include <asm/mach-powertv/asic_regs.h>
50 #include <asm/mach-powertv/interrupts.h>
52 #ifdef CONFIG_BOOTLOADER_DRIVER
53 #include <asm/mach-powertv/kbldr.h>
55 #include <asm/bootinfo.h>
57 #define BOOTLDRFAMILY(byte1, byte0) (((byte1) << 8) | (byte0))
62 static void pmem_setup_resource(void);
69 unsigned int platform_features
;
70 unsigned int platform_family
;
71 struct register_map _asic_register_map
;
72 EXPORT_SYMBOL(_asic_register_map
); /* Exported for testing */
73 unsigned long asic_phy_base
;
74 unsigned long asic_base
;
75 EXPORT_SYMBOL(asic_base
); /* Exported for testing */
76 struct resource
*gp_resources
;
77 static bool usb_configured
;
80 * Don't recommend to use it directly, it is usually used by kernel internally.
81 * Portable code should be using interfaces such as ioremp, dma_map_single, etc.
83 unsigned long phys_to_dma_offset
;
84 EXPORT_SYMBOL(phys_to_dma_offset
);
88 * IO Resource Definition
92 struct resource asic_resource
= {
93 .name
= "ASIC Resource",
96 .flags
= IORESOURCE_MEM
,
101 * USB Host Resource Definition
105 static struct resource ehci_resources
[] = {
107 .parent
= &asic_resource
,
110 .flags
= IORESOURCE_MEM
,
113 .start
= irq_usbehci
,
115 .flags
= IORESOURCE_IRQ
,
119 static u64 ehci_dmamask
= DMA_BIT_MASK(32);
121 static struct platform_device ehci_device
= {
122 .name
= "powertv-ehci",
125 .resource
= ehci_resources
,
127 .dma_mask
= &ehci_dmamask
,
128 .coherent_dma_mask
= DMA_BIT_MASK(32),
132 static struct resource ohci_resources
[] = {
134 .parent
= &asic_resource
,
137 .flags
= IORESOURCE_MEM
,
140 .start
= irq_usbohci
,
142 .flags
= IORESOURCE_IRQ
,
146 static u64 ohci_dmamask
= DMA_BIT_MASK(32);
148 static struct platform_device ohci_device
= {
149 .name
= "powertv-ohci",
152 .resource
= ohci_resources
,
154 .dma_mask
= &ohci_dmamask
,
155 .coherent_dma_mask
= DMA_BIT_MASK(32),
159 static struct platform_device
*platform_devices
[] = {
166 * Platform Configuration and Device Initialization
169 static void __init
fs_update(int pe
, int md
, int sdiv
, int disable_div_by_3
)
171 int en_prg
, byp
, pwr
, nsb
, val
;
180 val
= ((sdiv
<< 29) | (md
<< 24) | (pe
<<8) | (sout
<<3) | (byp
<<2) |
181 (nsb
<<1) | (disable_div_by_3
<<5));
183 asic_write(val
, usb_fs
);
184 asic_write(val
| (en_prg
<<4), usb_fs
);
185 asic_write(val
| (en_prg
<<4) | pwr
, usb_fs
);
189 * Allow override of bootloader-specified model
191 static char __initdata cmdline
[COMMAND_LINE_SIZE
];
193 #define FORCEFAMILY_PARAM "forcefamily"
195 static __init
int check_forcefamily(unsigned char forced_family
[2])
199 forced_family
[0] = '\0';
200 forced_family
[1] = '\0';
202 /* Check the command line for a forcefamily directive */
203 strncpy(cmdline
, arcs_cmdline
, COMMAND_LINE_SIZE
- 1);
204 p
= strstr(cmdline
, FORCEFAMILY_PARAM
);
205 if (p
&& (p
!= cmdline
) && (*(p
- 1) != ' '))
206 p
= strstr(p
, " " FORCEFAMILY_PARAM
"=");
209 p
+= strlen(FORCEFAMILY_PARAM
"=");
211 if (*p
== '\0' || *(p
+ 1) == '\0' ||
212 (*(p
+ 2) != '\0' && *(p
+ 2) != ' '))
213 pr_err(FORCEFAMILY_PARAM
" must be exactly two "
214 "characters long, ignoring value\n");
217 forced_family
[0] = *p
;
218 forced_family
[1] = *(p
+ 1);
226 * platform_set_family - determine major platform family type.
228 * Returns family type; -1 if none
229 * Returns the family type; -1 if none
232 static __init noinline
void platform_set_family(void)
234 #define BOOTLDRFAMILY(byte1, byte0) (((byte1) << 8) | (byte0))
236 unsigned char forced_family
[2];
237 unsigned short bootldr_family
;
239 check_forcefamily(forced_family
);
241 if (forced_family
[0] != '\0' && forced_family
[1] != '\0')
242 bootldr_family
= BOOTLDRFAMILY(forced_family
[0],
246 #ifdef CONFIG_BOOTLOADER_DRIVER
247 bootldr_family
= (unsigned short) kbldr_GetSWFamily();
249 #if defined(CONFIG_BOOTLOADER_FAMILY)
250 bootldr_family
= (unsigned short) BOOTLDRFAMILY(
251 CONFIG_BOOTLOADER_FAMILY
[0],
252 CONFIG_BOOTLOADER_FAMILY
[1]);
254 #error "Unknown Bootloader Family"
259 pr_info("Bootloader Family = 0x%04X\n", bootldr_family
);
261 switch (bootldr_family
) {
262 case BOOTLDRFAMILY('R', '1'):
263 platform_family
= FAMILY_1500
;
265 case BOOTLDRFAMILY('4', '4'):
266 platform_family
= FAMILY_4500
;
268 case BOOTLDRFAMILY('4', '6'):
269 platform_family
= FAMILY_4600
;
271 case BOOTLDRFAMILY('A', '1'):
272 platform_family
= FAMILY_4600VZA
;
274 case BOOTLDRFAMILY('8', '5'):
275 platform_family
= FAMILY_8500
;
277 case BOOTLDRFAMILY('R', '2'):
278 platform_family
= FAMILY_8500RNG
;
280 case BOOTLDRFAMILY('8', '6'):
281 platform_family
= FAMILY_8600
;
283 case BOOTLDRFAMILY('B', '1'):
284 platform_family
= FAMILY_8600VZB
;
286 case BOOTLDRFAMILY('E', '1'):
287 platform_family
= FAMILY_1500VZE
;
289 case BOOTLDRFAMILY('F', '1'):
290 platform_family
= FAMILY_1500VZF
;
293 platform_family
= -1;
297 unsigned int platform_get_family(void)
299 return platform_family
;
301 EXPORT_SYMBOL(platform_get_family
);
304 * \brief usb_eye_configure() for optimizing the USB eye on Calliope.
306 * \param unsigned int value saved to the register.
311 static void __init
usb_eye_configure(unsigned int value
)
313 asic_write(asic_read(crt_spare
) | value
, crt_spare
);
317 * platform_get_asic - determine the ASIC type.
321 * \return ASIC type; ASIC_UNKNOWN if none
324 enum asic_type
platform_get_asic(void)
328 EXPORT_SYMBOL(platform_get_asic
);
331 * platform_configure_usb - usb configuration based on platform type.
332 * @bcm1_usb2_ctl: value for the BCM1_USB2_CTL register, which is
335 static void __init
platform_configure_usb(void)
345 case ASIC_CRONUSLITE
:
346 fs_update(0x0000, 0x11, 0x02, 0);
347 bcm1_usb2_ctl
= 0x803;
351 fs_update(0x0000, 0x11, 0x02, 1);
353 switch (platform_family
) {
358 usb_eye_configure(0x003c0000);
362 usb_eye_configure(0x00300000);
366 bcm1_usb2_ctl
= 0x803;
370 pr_err("Unknown ASIC type: %d\n", asic
);
374 /* turn on USB power */
375 asic_write(0, usb2_strap
);
376 /* Enable all OHCI interrupts */
377 asic_write(bcm1_usb2_ctl
, usb2_control
);
378 /* USB2_STBUS_OBC store32/load32 */
379 asic_write(3, usb2_stbus_obc
);
380 /* USB2_STBUS_MESS_SIZE 2 packets */
381 asic_write(1, usb2_stbus_mess_size
);
382 /* USB2_STBUS_CHUNK_SIZE 2 packets */
383 asic_write(1, usb2_stbus_chunk_size
);
385 usb_configured
= true;
389 * Set up the USB EHCI interface
391 void platform_configure_usb_ehci()
393 platform_configure_usb();
397 * Set up the USB OHCI interface
399 void platform_configure_usb_ohci()
401 platform_configure_usb();
405 * Shut the USB EHCI interface down--currently a NOP
407 void platform_unconfigure_usb_ehci()
412 * Shut the USB OHCI interface down--currently a NOP
414 void platform_unconfigure_usb_ohci()
418 static void __init
set_register_map(unsigned long phys_base
,
419 const struct register_map
*map
)
421 asic_phy_base
= phys_base
;
422 _asic_register_map
= *map
;
423 register_map_virtualize(&_asic_register_map
);
424 asic_base
= (unsigned long)ioremap_nocache(phys_base
, ASIC_IO_SIZE
);
428 * configure_platform - configuration based on platform type.
430 void __init
configure_platform(void)
432 platform_set_family();
434 switch (platform_family
) {
438 platform_features
= FFS_CAPABLE
;
439 asic
= ASIC_CALLIOPE
;
440 set_register_map(CALLIOPE_IO_BASE
, &calliope_register_map
);
442 if (platform_family
== FAMILY_1500VZE
) {
443 gp_resources
= non_dvr_vze_calliope_resources
;
444 pr_info("Platform: 1500/Vz Class E - "
445 "CALLIOPE, NON_DVR_CAPABLE\n");
446 } else if (platform_family
== FAMILY_1500VZF
) {
447 gp_resources
= non_dvr_vzf_calliope_resources
;
448 pr_info("Platform: 1500/Vz Class F - "
449 "CALLIOPE, NON_DVR_CAPABLE\n");
451 gp_resources
= non_dvr_calliope_resources
;
452 pr_info("Platform: 1500/RNG100 - CALLIOPE, "
453 "NON_DVR_CAPABLE\n");
458 platform_features
= FFS_CAPABLE
| PCIE_CAPABLE
|
461 set_register_map(ZEUS_IO_BASE
, &zeus_register_map
);
462 gp_resources
= non_dvr_zeus_resources
;
464 pr_info("Platform: 4500 - ZEUS, NON_DVR_CAPABLE\n");
469 unsigned int chipversion
= 0;
471 /* The settop has PCIE but it isn't used, so don't advertise
473 platform_features
= FFS_CAPABLE
| DISPLAY_CAPABLE
;
475 /* Cronus and Cronus Lite have the same register map */
476 set_register_map(CRONUS_IO_BASE
, &cronus_register_map
);
478 /* ASIC version will determine if this is a real CronusLite or
479 * Castrati(Cronus) */
480 chipversion
= asic_read(chipver3
) << 24;
481 chipversion
|= asic_read(chipver2
) << 16;
482 chipversion
|= asic_read(chipver1
) << 8;
483 chipversion
|= asic_read(chipver0
);
485 if ((chipversion
== CRONUS_10
) || (chipversion
== CRONUS_11
))
488 asic
= ASIC_CRONUSLITE
;
490 gp_resources
= non_dvr_cronuslite_resources
;
491 pr_info("Platform: 4600 - %s, NON_DVR_CAPABLE, "
492 "chipversion=0x%08X\n",
493 (asic
== ASIC_CRONUS
) ? "CRONUS" : "CRONUS LITE",
498 platform_features
= FFS_CAPABLE
| DISPLAY_CAPABLE
;
500 set_register_map(CRONUS_IO_BASE
, &cronus_register_map
);
501 gp_resources
= non_dvr_cronus_resources
;
503 pr_info("Platform: Vz Class A - CRONUS, NON_DVR_CAPABLE\n");
508 platform_features
= DVR_CAPABLE
| PCIE_CAPABLE
|
511 set_register_map(ZEUS_IO_BASE
, &zeus_register_map
);
512 gp_resources
= dvr_zeus_resources
;
514 pr_info("Platform: 8500/RNG200 - ZEUS, DVR_CAPABLE\n");
519 platform_features
= DVR_CAPABLE
| PCIE_CAPABLE
|
522 set_register_map(CRONUS_IO_BASE
, &cronus_register_map
);
523 gp_resources
= dvr_cronus_resources
;
525 pr_info("Platform: 8600/Vz Class B - CRONUS, "
530 pr_crit("Platform: UNKNOWN PLATFORM\n");
536 phys_to_dma_offset
= 0x30000000;
539 phys_to_dma_offset
= 0x10000000;
541 case ASIC_CRONUSLITE
:
545 * TODO: We suppose 0x10000000 aliases into 0x20000000-
546 * 0x2XXXXXXX. If 0x10000000 aliases into 0x60000000-
547 * 0x6XXXXXXX, the offset should be 0x50000000, not 0x10000000.
549 phys_to_dma_offset
= 0x10000000;
552 phys_to_dma_offset
= 0x00000000;
558 * platform_devices_init - sets up USB device resourse.
560 static int __init
platform_devices_init(void)
562 pr_notice("%s: ----- Initializing USB resources -----\n", __func__
);
564 asic_resource
.start
= asic_phy_base
;
565 asic_resource
.end
+= asic_resource
.start
;
567 ehci_resources
[0].start
= asic_reg_phys_addr(ehci_hcapbase
);
568 ehci_resources
[0].end
+= ehci_resources
[0].start
;
570 ohci_resources
[0].start
= asic_reg_phys_addr(ohci_hc_revision
);
571 ohci_resources
[0].end
+= ohci_resources
[0].start
;
575 platform_add_devices(platform_devices
, ARRAY_SIZE(platform_devices
));
580 arch_initcall(platform_devices_init
);
588 * Allocates/reserves the Platform memory resources early in the boot process.
589 * This ignores any resources that are designated IORESOURCE_IO
591 void __init
platform_alloc_bootmem(void)
596 /* Get persistent memory data from command line before allocating
597 * resources. This need to happen before normal command line parsing
599 pmem_setup_resource();
601 /* Loop through looking for resources that want a particular address */
602 for (i
= 0; gp_resources
[i
].flags
!= 0; i
++) {
603 int size
= gp_resources
[i
].end
- gp_resources
[i
].start
+ 1;
604 if ((gp_resources
[i
].start
!= 0) &&
605 ((gp_resources
[i
].flags
& IORESOURCE_MEM
) != 0)) {
606 reserve_bootmem(dma_to_phys(gp_resources
[i
].start
),
608 total
+= gp_resources
[i
].end
-
609 gp_resources
[i
].start
+ 1;
610 pr_info("reserve resource %s at %08x (%u bytes)\n",
611 gp_resources
[i
].name
, gp_resources
[i
].start
,
612 gp_resources
[i
].end
-
613 gp_resources
[i
].start
+ 1);
617 /* Loop through assigning addresses for those that are left */
618 for (i
= 0; gp_resources
[i
].flags
!= 0; i
++) {
619 int size
= gp_resources
[i
].end
- gp_resources
[i
].start
+ 1;
620 if ((gp_resources
[i
].start
== 0) &&
621 ((gp_resources
[i
].flags
& IORESOURCE_MEM
) != 0)) {
622 void *mem
= alloc_bootmem_pages(size
);
625 pr_err("Unable to allocate bootmem pages "
626 "for %s\n", gp_resources
[i
].name
);
629 gp_resources
[i
].start
=
630 phys_to_dma(virt_to_phys(mem
));
631 gp_resources
[i
].end
=
632 gp_resources
[i
].start
+ size
- 1;
634 pr_info("allocate resource %s at %08x "
636 gp_resources
[i
].name
,
637 gp_resources
[i
].start
, size
);
642 pr_info("Total Platform driver memory allocation: 0x%08x\n", total
);
644 /* indicate resources that are platform I/O related */
645 for (i
= 0; gp_resources
[i
].flags
!= 0; i
++) {
646 if ((gp_resources
[i
].start
!= 0) &&
647 ((gp_resources
[i
].flags
& IORESOURCE_IO
) != 0)) {
648 pr_info("reserved platform resource %s at %08x\n",
649 gp_resources
[i
].name
, gp_resources
[i
].start
);
656 * PERSISTENT MEMORY (PMEM) CONFIGURATION
659 static unsigned long pmemaddr __initdata
;
661 static int __init
early_param_pmemaddr(char *p
)
663 pmemaddr
= (unsigned long)simple_strtoul(p
, NULL
, 0);
666 early_param("pmemaddr", early_param_pmemaddr
);
668 static long pmemlen __initdata
;
670 static int __init
early_param_pmemlen(char *p
)
672 /* TODO: we can use this code when and if the bootloader ever changes this */
674 pmemlen
= (unsigned long)simple_strtoul(p
, NULL
, 0);
680 early_param("pmemlen", early_param_pmemlen
);
683 * Set up persistent memory. If we were given values, we patch the array of
684 * resources. Otherwise, persistent memory may be allocated anywhere at all.
686 static void __init
pmem_setup_resource(void)
688 struct resource
*resource
;
689 resource
= asic_resource_get("DiagPersistentMemory");
691 if (resource
&& pmemaddr
&& pmemlen
) {
692 /* The address provided by bootloader is in kseg0. Convert to
694 resource
->start
= phys_to_dma(pmemaddr
- 0x80000000);
695 resource
->end
= resource
->start
+ pmemlen
- 1;
697 pr_info("persistent memory: start=0x%x end=0x%x\n",
698 resource
->start
, resource
->end
);
704 * RESOURCE ACCESS FUNCTIONS
709 * asic_resource_get - retrieves parameters for a platform resource.
710 * @name: string to match resource
712 * Returns a pointer to a struct resource corresponding to the given name.
714 * CANNOT BE NAMED platform_resource_get, which would be the obvious choice,
715 * as this function name is already declared
717 struct resource
*asic_resource_get(const char *name
)
721 for (i
= 0; gp_resources
[i
].flags
!= 0; i
++) {
722 if (strcmp(gp_resources
[i
].name
, name
) == 0)
723 return &gp_resources
[i
];
728 EXPORT_SYMBOL(asic_resource_get
);
731 * platform_release_memory - release pre-allocated memory
732 * @ptr: pointer to memory to release
733 * @size: size of resource
735 * This must only be called for memory allocated or reserved via the boot
738 void platform_release_memory(void *ptr
, int size
)
743 addr
= ((unsigned long)ptr
+ (PAGE_SIZE
- 1)) & PAGE_MASK
;
744 end
= ((unsigned long)ptr
+ size
) & PAGE_MASK
;
746 for (; addr
< end
; addr
+= PAGE_SIZE
) {
747 ClearPageReserved(virt_to_page(__va(addr
)));
748 init_page_count(virt_to_page(__va(addr
)));
749 free_page((unsigned long)__va(addr
));
752 EXPORT_SYMBOL(platform_release_memory
);
756 * FEATURE AVAILABILITY FUNCTIONS
759 int platform_supports_dvr(void)
761 return (platform_features
& DVR_CAPABLE
) != 0;
764 int platform_supports_ffs(void)
766 return (platform_features
& FFS_CAPABLE
) != 0;
769 int platform_supports_pcie(void)
771 return (platform_features
& PCIE_CAPABLE
) != 0;
774 int platform_supports_display(void)
776 return (platform_features
& DISPLAY_CAPABLE
) != 0;