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>
43 #include <linux/swap.h>
44 #include <linux/highmem.h>
45 #include <linux/dma-mapping.h>
47 #include <asm/mach-powertv/asic.h>
48 #include <asm/mach-powertv/asic_regs.h>
49 #include <asm/mach-powertv/interrupts.h>
51 #ifdef CONFIG_BOOTLOADER_DRIVER
52 #include <asm/mach-powertv/kbldr.h>
54 #include <asm/bootinfo.h>
56 #define BOOTLDRFAMILY(byte1, byte0) (((byte1) << 8) | (byte0))
61 static void pmem_setup_resource(void);
68 unsigned int platform_features
;
69 unsigned int platform_family
;
70 const struct register_map
*register_map
;
71 EXPORT_SYMBOL(register_map
); /* Exported for testing */
72 unsigned long asic_phy_base
;
73 unsigned long asic_base
;
74 EXPORT_SYMBOL(asic_base
); /* Exported for testing */
75 struct resource
*gp_resources
;
76 static bool usb_configured
;
79 * Don't recommend to use it directly, it is usually used by kernel internally.
80 * Portable code should be using interfaces such as ioremp, dma_map_single, etc.
82 unsigned long phys_to_bus_offset
;
83 EXPORT_SYMBOL(phys_to_bus_offset
);
87 * IO Resource Definition
91 struct resource asic_resource
= {
92 .name
= "ASIC Resource",
95 .flags
= IORESOURCE_MEM
,
100 * USB Host Resource Definition
104 static struct resource ehci_resources
[] = {
106 .parent
= &asic_resource
,
109 .flags
= IORESOURCE_MEM
,
112 .start
= irq_usbehci
,
114 .flags
= IORESOURCE_IRQ
,
118 static u64 ehci_dmamask
= DMA_BIT_MASK(32);
120 static struct platform_device ehci_device
= {
121 .name
= "powertv-ehci",
124 .resource
= ehci_resources
,
126 .dma_mask
= &ehci_dmamask
,
127 .coherent_dma_mask
= DMA_BIT_MASK(32),
131 static struct resource ohci_resources
[] = {
133 .parent
= &asic_resource
,
136 .flags
= IORESOURCE_MEM
,
139 .start
= irq_usbohci
,
141 .flags
= IORESOURCE_IRQ
,
145 static u64 ohci_dmamask
= DMA_BIT_MASK(32);
147 static struct platform_device ohci_device
= {
148 .name
= "powertv-ohci",
151 .resource
= ohci_resources
,
153 .dma_mask
= &ohci_dmamask
,
154 .coherent_dma_mask
= DMA_BIT_MASK(32),
158 static struct platform_device
*platform_devices
[] = {
165 * Platform Configuration and Device Initialization
168 static void __init
fs_update(int pe
, int md
, int sdiv
, int disable_div_by_3
)
170 int en_prg
, byp
, pwr
, nsb
, val
;
179 val
= ((sdiv
<< 29) | (md
<< 24) | (pe
<<8) | (sout
<<3) | (byp
<<2) |
180 (nsb
<<1) | (disable_div_by_3
<<5));
182 asic_write(val
, usb_fs
);
183 asic_write(val
| (en_prg
<<4), usb_fs
);
184 asic_write(val
| (en_prg
<<4) | pwr
, usb_fs
);
188 * Allow override of bootloader-specified model
190 static char __initdata cmdline
[COMMAND_LINE_SIZE
];
192 #define FORCEFAMILY_PARAM "forcefamily"
194 static __init
int check_forcefamily(unsigned char forced_family
[2])
198 forced_family
[0] = '\0';
199 forced_family
[1] = '\0';
201 /* Check the command line for a forcefamily directive */
202 strncpy(cmdline
, arcs_cmdline
, COMMAND_LINE_SIZE
- 1);
203 p
= strstr(cmdline
, FORCEFAMILY_PARAM
);
204 if (p
&& (p
!= cmdline
) && (*(p
- 1) != ' '))
205 p
= strstr(p
, " " FORCEFAMILY_PARAM
"=");
208 p
+= strlen(FORCEFAMILY_PARAM
"=");
210 if (*p
== '\0' || *(p
+ 1) == '\0' ||
211 (*(p
+ 2) != '\0' && *(p
+ 2) != ' '))
212 pr_err(FORCEFAMILY_PARAM
" must be exactly two "
213 "characters long, ignoring value\n");
216 forced_family
[0] = *p
;
217 forced_family
[1] = *(p
+ 1);
225 * platform_set_family - determine major platform family type.
227 * Returns family type; -1 if none
228 * Returns the family type; -1 if none
231 static __init noinline
void platform_set_family(void)
233 #define BOOTLDRFAMILY(byte1, byte0) (((byte1) << 8) | (byte0))
235 unsigned char forced_family
[2];
236 unsigned short bootldr_family
;
238 check_forcefamily(forced_family
);
240 if (forced_family
[0] != '\0' && forced_family
[1] != '\0')
241 bootldr_family
= BOOTLDRFAMILY(forced_family
[0],
245 #ifdef CONFIG_BOOTLOADER_DRIVER
246 bootldr_family
= (unsigned short) kbldr_GetSWFamily();
248 #if defined(CONFIG_BOOTLOADER_FAMILY)
249 bootldr_family
= (unsigned short) BOOTLDRFAMILY(
250 CONFIG_BOOTLOADER_FAMILY
[0],
251 CONFIG_BOOTLOADER_FAMILY
[1]);
253 #error "Unknown Bootloader Family"
258 pr_info("Bootloader Family = 0x%04X\n", bootldr_family
);
260 switch (bootldr_family
) {
261 case BOOTLDRFAMILY('R', '1'):
262 platform_family
= FAMILY_1500
;
264 case BOOTLDRFAMILY('4', '4'):
265 platform_family
= FAMILY_4500
;
267 case BOOTLDRFAMILY('4', '6'):
268 platform_family
= FAMILY_4600
;
270 case BOOTLDRFAMILY('A', '1'):
271 platform_family
= FAMILY_4600VZA
;
273 case BOOTLDRFAMILY('8', '5'):
274 platform_family
= FAMILY_8500
;
276 case BOOTLDRFAMILY('R', '2'):
277 platform_family
= FAMILY_8500RNG
;
279 case BOOTLDRFAMILY('8', '6'):
280 platform_family
= FAMILY_8600
;
282 case BOOTLDRFAMILY('B', '1'):
283 platform_family
= FAMILY_8600VZB
;
285 case BOOTLDRFAMILY('E', '1'):
286 platform_family
= FAMILY_1500VZE
;
288 case BOOTLDRFAMILY('F', '1'):
289 platform_family
= FAMILY_1500VZF
;
292 platform_family
= -1;
296 unsigned int platform_get_family(void)
298 return platform_family
;
300 EXPORT_SYMBOL(platform_get_family
);
303 * \brief usb_eye_configure() for optimizing the USB eye on Calliope.
305 * \param unsigned int value saved to the register.
310 static void __init
usb_eye_configure(unsigned int value
)
312 asic_write(asic_read(crt_spare
) | value
, crt_spare
);
316 * platform_get_asic - determine the ASIC type.
320 * \return ASIC type; ASIC_UNKNOWN if none
323 enum asic_type
platform_get_asic(void)
327 EXPORT_SYMBOL(platform_get_asic
);
330 * platform_configure_usb - usb configuration based on platform type.
331 * @bcm1_usb2_ctl: value for the BCM1_USB2_CTL register, which is
334 static void __init
platform_configure_usb(void)
343 fs_update(0x0000, 0x11, 0x02, 0);
344 bcm1_usb2_ctl
= 0x803;
348 case ASIC_CRONUSLITE
:
349 fs_update(0x0000, 0x11, 0x02, 0);
350 bcm1_usb2_ctl
= 0x803;
354 fs_update(0x0000, 0x11, 0x02, 1);
356 switch (platform_family
) {
361 usb_eye_configure(0x003c0000);
365 usb_eye_configure(0x00300000);
369 bcm1_usb2_ctl
= 0x803;
373 pr_err("Unknown ASIC type: %d\n", asic
);
377 /* turn on USB power */
378 asic_write(0, usb2_strap
);
379 /* Enable all OHCI interrupts */
380 asic_write(bcm1_usb2_ctl
, usb2_control
);
381 /* USB2_STBUS_OBC store32/load32 */
382 asic_write(3, usb2_stbus_obc
);
383 /* USB2_STBUS_MESS_SIZE 2 packets */
384 asic_write(1, usb2_stbus_mess_size
);
385 /* USB2_STBUS_CHUNK_SIZE 2 packets */
386 asic_write(1, usb2_stbus_chunk_size
);
388 usb_configured
= true;
392 * Set up the USB EHCI interface
394 void platform_configure_usb_ehci()
396 platform_configure_usb();
400 * Set up the USB OHCI interface
402 void platform_configure_usb_ohci()
404 platform_configure_usb();
408 * Shut the USB EHCI interface down--currently a NOP
410 void platform_unconfigure_usb_ehci()
415 * Shut the USB OHCI interface down--currently a NOP
417 void platform_unconfigure_usb_ohci()
422 * configure_platform - configuration based on platform type.
424 void __init
configure_platform(void)
426 platform_set_family();
428 switch (platform_family
) {
432 platform_features
= FFS_CAPABLE
;
433 asic
= ASIC_CALLIOPE
;
434 asic_phy_base
= CALLIOPE_IO_BASE
;
435 register_map
= &calliope_register_map
;
436 asic_base
= (unsigned long)ioremap_nocache(asic_phy_base
,
439 if (platform_family
== FAMILY_1500VZE
) {
440 gp_resources
= non_dvr_vze_calliope_resources
;
441 pr_info("Platform: 1500/Vz Class E - "
442 "CALLIOPE, NON_DVR_CAPABLE\n");
443 } else if (platform_family
== FAMILY_1500VZF
) {
444 gp_resources
= non_dvr_vzf_calliope_resources
;
445 pr_info("Platform: 1500/Vz Class F - "
446 "CALLIOPE, NON_DVR_CAPABLE\n");
448 gp_resources
= non_dvr_calliope_resources
;
449 pr_info("Platform: 1500/RNG100 - CALLIOPE, "
450 "NON_DVR_CAPABLE\n");
455 platform_features
= FFS_CAPABLE
| PCIE_CAPABLE
|
458 asic_phy_base
= ZEUS_IO_BASE
;
459 register_map
= &zeus_register_map
;
460 asic_base
= (unsigned long)ioremap_nocache(asic_phy_base
,
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
;
474 asic_phy_base
= CRONUS_IO_BASE
; /* same as Cronus */
475 register_map
= &cronus_register_map
; /* same as Cronus */
476 asic_base
= (unsigned long)ioremap_nocache(asic_phy_base
,
478 gp_resources
= non_dvr_cronuslite_resources
;
480 /* ASIC version will determine if this is a real CronusLite or
481 * Castrati(Cronus) */
482 chipversion
= asic_read(chipver3
) << 24;
483 chipversion
|= asic_read(chipver2
) << 16;
484 chipversion
|= asic_read(chipver1
) << 8;
485 chipversion
|= asic_read(chipver0
);
487 if ((chipversion
== CRONUS_10
) || (chipversion
== CRONUS_11
))
490 asic
= ASIC_CRONUSLITE
;
492 pr_info("Platform: 4600 - %s, NON_DVR_CAPABLE, "
493 "chipversion=0x%08X\n",
494 (asic
== ASIC_CRONUS
) ? "CRONUS" : "CRONUS LITE",
499 platform_features
= FFS_CAPABLE
| DISPLAY_CAPABLE
;
501 asic_phy_base
= CRONUS_IO_BASE
;
502 register_map
= &cronus_register_map
;
503 asic_base
= (unsigned long)ioremap_nocache(asic_phy_base
,
505 gp_resources
= non_dvr_cronus_resources
;
507 pr_info("Platform: Vz Class A - CRONUS, NON_DVR_CAPABLE\n");
512 platform_features
= DVR_CAPABLE
| PCIE_CAPABLE
|
515 asic_phy_base
= ZEUS_IO_BASE
;
516 register_map
= &zeus_register_map
;
517 asic_base
= (unsigned long)ioremap_nocache(asic_phy_base
,
519 gp_resources
= dvr_zeus_resources
;
521 pr_info("Platform: 8500/RNG200 - ZEUS, DVR_CAPABLE\n");
526 platform_features
= DVR_CAPABLE
| PCIE_CAPABLE
|
529 asic_phy_base
= CRONUS_IO_BASE
;
530 register_map
= &cronus_register_map
;
531 asic_base
= (unsigned long)ioremap_nocache(asic_phy_base
,
533 gp_resources
= dvr_cronus_resources
;
535 pr_info("Platform: 8600/Vz Class B - CRONUS, "
540 pr_crit("Platform: UNKNOWN PLATFORM\n");
546 phys_to_bus_offset
= 0x30000000;
549 phys_to_bus_offset
= 0x10000000;
551 case ASIC_CRONUSLITE
:
555 * TODO: We suppose 0x10000000 aliases into 0x20000000-
556 * 0x2XXXXXXX. If 0x10000000 aliases into 0x60000000-
557 * 0x6XXXXXXX, the offset should be 0x50000000, not 0x10000000.
559 phys_to_bus_offset
= 0x10000000;
562 phys_to_bus_offset
= 0x00000000;
568 * platform_devices_init - sets up USB device resourse.
570 static int __init
platform_devices_init(void)
572 pr_notice("%s: ----- Initializing USB resources -----\n", __func__
);
574 asic_resource
.start
= asic_phy_base
;
575 asic_resource
.end
+= asic_resource
.start
;
577 ehci_resources
[0].start
= asic_reg_phys_addr(ehci_hcapbase
);
578 ehci_resources
[0].end
+= ehci_resources
[0].start
;
580 ohci_resources
[0].start
= asic_reg_phys_addr(ohci_hc_revision
);
581 ohci_resources
[0].end
+= ohci_resources
[0].start
;
585 platform_add_devices(platform_devices
, ARRAY_SIZE(platform_devices
));
590 arch_initcall(platform_devices_init
);
598 * Allocates/reserves the Platform memory resources early in the boot process.
599 * This ignores any resources that are designated IORESOURCE_IO
601 void __init
platform_alloc_bootmem(void)
606 /* Get persistent memory data from command line before allocating
607 * resources. This need to happen before normal command line parsing
609 pmem_setup_resource();
611 /* Loop through looking for resources that want a particular address */
612 for (i
= 0; gp_resources
[i
].flags
!= 0; i
++) {
613 int size
= gp_resources
[i
].end
- gp_resources
[i
].start
+ 1;
614 if ((gp_resources
[i
].start
!= 0) &&
615 ((gp_resources
[i
].flags
& IORESOURCE_MEM
) != 0)) {
616 reserve_bootmem(bus_to_phys(gp_resources
[i
].start
),
618 total
+= gp_resources
[i
].end
-
619 gp_resources
[i
].start
+ 1;
620 pr_info("reserve resource %s at %08x (%u bytes)\n",
621 gp_resources
[i
].name
, gp_resources
[i
].start
,
622 gp_resources
[i
].end
-
623 gp_resources
[i
].start
+ 1);
627 /* Loop through assigning addresses for those that are left */
628 for (i
= 0; gp_resources
[i
].flags
!= 0; i
++) {
629 int size
= gp_resources
[i
].end
- gp_resources
[i
].start
+ 1;
630 if ((gp_resources
[i
].start
== 0) &&
631 ((gp_resources
[i
].flags
& IORESOURCE_MEM
) != 0)) {
632 void *mem
= alloc_bootmem_pages(size
);
635 pr_err("Unable to allocate bootmem pages "
636 "for %s\n", gp_resources
[i
].name
);
639 gp_resources
[i
].start
=
640 phys_to_bus(virt_to_phys(mem
));
641 gp_resources
[i
].end
=
642 gp_resources
[i
].start
+ size
- 1;
644 pr_info("allocate resource %s at %08x "
646 gp_resources
[i
].name
,
647 gp_resources
[i
].start
, size
);
652 pr_info("Total Platform driver memory allocation: 0x%08x\n", total
);
654 /* indicate resources that are platform I/O related */
655 for (i
= 0; gp_resources
[i
].flags
!= 0; i
++) {
656 if ((gp_resources
[i
].start
!= 0) &&
657 ((gp_resources
[i
].flags
& IORESOURCE_IO
) != 0)) {
658 pr_info("reserved platform resource %s at %08x\n",
659 gp_resources
[i
].name
, gp_resources
[i
].start
);
666 * PERSISTENT MEMORY (PMEM) CONFIGURATION
669 static unsigned long pmemaddr __initdata
;
671 static int __init
early_param_pmemaddr(char *p
)
673 pmemaddr
= (unsigned long)simple_strtoul(p
, NULL
, 0);
676 early_param("pmemaddr", early_param_pmemaddr
);
678 static long pmemlen __initdata
;
680 static int __init
early_param_pmemlen(char *p
)
682 /* TODO: we can use this code when and if the bootloader ever changes this */
684 pmemlen
= (unsigned long)simple_strtoul(p
, NULL
, 0);
690 early_param("pmemlen", early_param_pmemlen
);
693 * Set up persistent memory. If we were given values, we patch the array of
694 * resources. Otherwise, persistent memory may be allocated anywhere at all.
696 static void __init
pmem_setup_resource(void)
698 struct resource
*resource
;
699 resource
= asic_resource_get("DiagPersistentMemory");
701 if (resource
&& pmemaddr
&& pmemlen
) {
702 /* The address provided by bootloader is in kseg0. Convert to
704 resource
->start
= phys_to_bus(pmemaddr
- 0x80000000);
705 resource
->end
= resource
->start
+ pmemlen
- 1;
707 pr_info("persistent memory: start=0x%x end=0x%x\n",
708 resource
->start
, resource
->end
);
714 * RESOURCE ACCESS FUNCTIONS
719 * asic_resource_get - retrieves parameters for a platform resource.
720 * @name: string to match resource
722 * Returns a pointer to a struct resource corresponding to the given name.
724 * CANNOT BE NAMED platform_resource_get, which would be the obvious choice,
725 * as this function name is already declared
727 struct resource
*asic_resource_get(const char *name
)
731 for (i
= 0; gp_resources
[i
].flags
!= 0; i
++) {
732 if (strcmp(gp_resources
[i
].name
, name
) == 0)
733 return &gp_resources
[i
];
738 EXPORT_SYMBOL(asic_resource_get
);
741 * platform_release_memory - release pre-allocated memory
742 * @ptr: pointer to memory to release
743 * @size: size of resource
745 * This must only be called for memory allocated or reserved via the boot
748 void platform_release_memory(void *ptr
, int size
)
753 addr
= ((unsigned long)ptr
+ (PAGE_SIZE
- 1)) & PAGE_MASK
;
754 end
= ((unsigned long)ptr
+ size
) & PAGE_MASK
;
756 for (; addr
< end
; addr
+= PAGE_SIZE
) {
757 ClearPageReserved(virt_to_page(__va(addr
)));
758 init_page_count(virt_to_page(__va(addr
)));
759 free_page((unsigned long)__va(addr
));
762 EXPORT_SYMBOL(platform_release_memory
);
766 * FEATURE AVAILABILITY FUNCTIONS
769 int platform_supports_dvr(void)
771 return (platform_features
& DVR_CAPABLE
) != 0;
774 int platform_supports_ffs(void)
776 return (platform_features
& FFS_CAPABLE
) != 0;
779 int platform_supports_pcie(void)
781 return (platform_features
& PCIE_CAPABLE
) != 0;
784 int platform_supports_display(void)
786 return (platform_features
& DISPLAY_CAPABLE
) != 0;