aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/include/asm/mach-powertv/asic_reg_map.h90
-rw-r--r--arch/mips/include/asm/mach-powertv/asic_regs.h135
-rw-r--r--arch/mips/powertv/asic/asic-calliope.c131
-rw-r--r--arch/mips/powertv/asic/asic-cronus.c131
-rw-r--r--arch/mips/powertv/asic/asic-zeus.c131
-rw-r--r--arch/mips/powertv/asic/asic_devices.c46
6 files changed, 361 insertions, 303 deletions
diff --git a/arch/mips/include/asm/mach-powertv/asic_reg_map.h b/arch/mips/include/asm/mach-powertv/asic_reg_map.h
new file mode 100644
index 000000000000..6f26cb09828e
--- /dev/null
+++ b/arch/mips/include/asm/mach-powertv/asic_reg_map.h
@@ -0,0 +1,90 @@
1/*
2 * asic_reg_map.h
3 *
4 * A macro-enclosed list of the elements for the register_map structure for
5 * use in defining and manipulating the structure.
6 *
7 * Copyright (C) 2009 Cisco Systems, Inc.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24REGISTER_MAP_ELEMENT(eic_slow0_strt_add)
25REGISTER_MAP_ELEMENT(eic_cfg_bits)
26REGISTER_MAP_ELEMENT(eic_ready_status)
27REGISTER_MAP_ELEMENT(chipver3)
28REGISTER_MAP_ELEMENT(chipver2)
29REGISTER_MAP_ELEMENT(chipver1)
30REGISTER_MAP_ELEMENT(chipver0)
31REGISTER_MAP_ELEMENT(uart1_intstat)
32REGISTER_MAP_ELEMENT(uart1_inten)
33REGISTER_MAP_ELEMENT(uart1_config1)
34REGISTER_MAP_ELEMENT(uart1_config2)
35REGISTER_MAP_ELEMENT(uart1_divisorhi)
36REGISTER_MAP_ELEMENT(uart1_divisorlo)
37REGISTER_MAP_ELEMENT(uart1_data)
38REGISTER_MAP_ELEMENT(uart1_status)
39REGISTER_MAP_ELEMENT(int_stat_3)
40REGISTER_MAP_ELEMENT(int_stat_2)
41REGISTER_MAP_ELEMENT(int_stat_1)
42REGISTER_MAP_ELEMENT(int_stat_0)
43REGISTER_MAP_ELEMENT(int_config)
44REGISTER_MAP_ELEMENT(int_int_scan)
45REGISTER_MAP_ELEMENT(ien_int_3)
46REGISTER_MAP_ELEMENT(ien_int_2)
47REGISTER_MAP_ELEMENT(ien_int_1)
48REGISTER_MAP_ELEMENT(ien_int_0)
49REGISTER_MAP_ELEMENT(int_level_3_3)
50REGISTER_MAP_ELEMENT(int_level_3_2)
51REGISTER_MAP_ELEMENT(int_level_3_1)
52REGISTER_MAP_ELEMENT(int_level_3_0)
53REGISTER_MAP_ELEMENT(int_level_2_3)
54REGISTER_MAP_ELEMENT(int_level_2_2)
55REGISTER_MAP_ELEMENT(int_level_2_1)
56REGISTER_MAP_ELEMENT(int_level_2_0)
57REGISTER_MAP_ELEMENT(int_level_1_3)
58REGISTER_MAP_ELEMENT(int_level_1_2)
59REGISTER_MAP_ELEMENT(int_level_1_1)
60REGISTER_MAP_ELEMENT(int_level_1_0)
61REGISTER_MAP_ELEMENT(int_level_0_3)
62REGISTER_MAP_ELEMENT(int_level_0_2)
63REGISTER_MAP_ELEMENT(int_level_0_1)
64REGISTER_MAP_ELEMENT(int_level_0_0)
65REGISTER_MAP_ELEMENT(int_docsis_en)
66REGISTER_MAP_ELEMENT(mips_pll_setup)
67REGISTER_MAP_ELEMENT(usb_fs)
68REGISTER_MAP_ELEMENT(test_bus)
69REGISTER_MAP_ELEMENT(crt_spare)
70REGISTER_MAP_ELEMENT(usb2_ohci_int_mask)
71REGISTER_MAP_ELEMENT(usb2_strap)
72REGISTER_MAP_ELEMENT(ehci_hcapbase)
73REGISTER_MAP_ELEMENT(ohci_hc_revision)
74REGISTER_MAP_ELEMENT(bcm1_bs_lmi_steer)
75REGISTER_MAP_ELEMENT(usb2_control)
76REGISTER_MAP_ELEMENT(usb2_stbus_obc)
77REGISTER_MAP_ELEMENT(usb2_stbus_mess_size)
78REGISTER_MAP_ELEMENT(usb2_stbus_chunk_size)
79REGISTER_MAP_ELEMENT(pcie_regs)
80REGISTER_MAP_ELEMENT(tim_ch)
81REGISTER_MAP_ELEMENT(tim_cl)
82REGISTER_MAP_ELEMENT(gpio_dout)
83REGISTER_MAP_ELEMENT(gpio_din)
84REGISTER_MAP_ELEMENT(gpio_dir)
85REGISTER_MAP_ELEMENT(watchdog)
86REGISTER_MAP_ELEMENT(front_panel)
87REGISTER_MAP_ELEMENT(misc_clk_ctl1)
88REGISTER_MAP_ELEMENT(misc_clk_ctl2)
89REGISTER_MAP_ELEMENT(crt_ext_ctl)
90REGISTER_MAP_ELEMENT(register_maps)
diff --git a/arch/mips/include/asm/mach-powertv/asic_regs.h b/arch/mips/include/asm/mach-powertv/asic_regs.h
index 9a65c93782f9..1e11236c6dbc 100644
--- a/arch/mips/include/asm/mach-powertv/asic_regs.h
+++ b/arch/mips/include/asm/mach-powertv/asic_regs.h
@@ -35,11 +35,12 @@ enum asic_type {
35#define CRONUS_11 0x0B4C1C21 35#define CRONUS_11 0x0B4C1C21
36#define CRONUSLITE_10 0x0B4C1C40 36#define CRONUSLITE_10 0x0B4C1C40
37 37
38#define NAND_FLASH_BASE 0x03000000 38#define NAND_FLASH_BASE 0x03000000
39#define ZEUS_IO_BASE 0x09000000
40#define CALLIOPE_IO_BASE 0x08000000 39#define CALLIOPE_IO_BASE 0x08000000
41#define CRONUS_IO_BASE 0x09000000 40#define CRONUS_IO_BASE 0x09000000
42#define ASIC_IO_SIZE 0x01000000 41#define ZEUS_IO_BASE 0x09000000
42
43#define ASIC_IO_SIZE 0x01000000
43 44
44/* Definitions for backward compatibility */ 45/* Definitions for backward compatibility */
45#define UART1_INTSTAT uart1_intstat 46#define UART1_INTSTAT uart1_intstat
@@ -52,96 +53,62 @@ enum asic_type {
52#define UART1_STATUS uart1_status 53#define UART1_STATUS uart1_status
53 54
54/* ASIC register enumeration */ 55/* ASIC register enumeration */
56union register_map_entry {
57 unsigned long phys;
58 u32 *virt;
59};
60
61#define REGISTER_MAP_ELEMENT(x) union register_map_entry x;
55struct register_map { 62struct register_map {
56 u32 eic_slow0_strt_add; 63#include <asm/mach-powertv/asic_reg_map.h>
57 u32 eic_cfg_bits;
58 u32 eic_ready_status;
59
60 u32 chipver3;
61 u32 chipver2;
62 u32 chipver1;
63 u32 chipver0;
64
65 u32 uart1_intstat;
66 u32 uart1_inten;
67 u32 uart1_config1;
68 u32 uart1_config2;
69 u32 uart1_divisorhi;
70 u32 uart1_divisorlo;
71 u32 uart1_data;
72 u32 uart1_status;
73
74 u32 int_stat_3;
75 u32 int_stat_2;
76 u32 int_stat_1;
77 u32 int_stat_0;
78 u32 int_config;
79 u32 int_int_scan;
80 u32 ien_int_3;
81 u32 ien_int_2;
82 u32 ien_int_1;
83 u32 ien_int_0;
84 u32 int_level_3_3;
85 u32 int_level_3_2;
86 u32 int_level_3_1;
87 u32 int_level_3_0;
88 u32 int_level_2_3;
89 u32 int_level_2_2;
90 u32 int_level_2_1;
91 u32 int_level_2_0;
92 u32 int_level_1_3;
93 u32 int_level_1_2;
94 u32 int_level_1_1;
95 u32 int_level_1_0;
96 u32 int_level_0_3;
97 u32 int_level_0_2;
98 u32 int_level_0_1;
99 u32 int_level_0_0;
100 u32 int_docsis_en;
101
102 u32 mips_pll_setup;
103 u32 usb_fs;
104 u32 test_bus;
105 u32 crt_spare;
106 u32 usb2_ohci_int_mask;
107 u32 usb2_strap;
108 u32 ehci_hcapbase;
109 u32 ohci_hc_revision;
110 u32 bcm1_bs_lmi_steer;
111 u32 usb2_control;
112 u32 usb2_stbus_obc;
113 u32 usb2_stbus_mess_size;
114 u32 usb2_stbus_chunk_size;
115
116 u32 pcie_regs;
117 u32 tim_ch;
118 u32 tim_cl;
119 u32 gpio_dout;
120 u32 gpio_din;
121 u32 gpio_dir;
122 u32 watchdog;
123 u32 front_panel;
124
125 u32 register_maps;
126}; 64};
65#undef REGISTER_MAP_ELEMENT
66
67/**
68 * register_map_offset_phys - add an offset to the physical address
69 * @map: Pointer to the &struct register_map
70 * @offset: Value to add
71 *
72 * Only adds the base to non-zero physical addresses
73 */
74static inline void register_map_offset_phys(struct register_map *map,
75 unsigned long offset)
76{
77#define REGISTER_MAP_ELEMENT(x) do { \
78 if (map->x.phys != 0) \
79 map->x.phys += offset; \
80 } while (false);
81
82#include <asm/mach-powertv/asic_reg_map.h>
83#undef REGISTER_MAP_ELEMENT
84}
85
86/**
87 * register_map_virtualize - Convert &register_map to virtual addresses
88 * @map: Pointer to &register_map to virtualize
89 */
90static inline void register_map_virtualize(struct register_map *map)
91{
92#define REGISTER_MAP_ELEMENT(x) do { \
93 map->x.virt = (!map->x.phys) ? NULL : \
94 UNCAC_ADDR(phys_to_virt(map->x.phys)); \
95 } while (false);
96
97#include <asm/mach-powertv/asic_reg_map.h>
98#undef REGISTER_MAP_ELEMENT
99}
127 100
128extern enum asic_type asic; 101extern struct register_map _asic_register_map;
129extern const struct register_map *register_map;
130extern unsigned long asic_phy_base; /* Physical address of ASIC */
131extern unsigned long asic_base; /* Virtual address of ASIC */
132 102
133/* 103/*
134 * Macros to interface to registers through their ioremapped address 104 * Macros to interface to registers through their ioremapped address
135 * asic_reg_offset Returns the offset of a given register from the start
136 * of the ASIC address space
137 * asic_reg_phys_addr Returns the physical address of the given register 105 * asic_reg_phys_addr Returns the physical address of the given register
138 * asic_reg_addr Returns the iomapped virtual address of the given 106 * asic_reg_addr Returns the iomapped virtual address of the given
139 * register. 107 * register.
140 */ 108 */
141#define asic_reg_offset(x) (register_map->x) 109#define asic_reg_addr(x) (_asic_register_map.x.virt)
142#define asic_reg_phys_addr(x) (asic_phy_base + asic_reg_offset(x)) 110#define asic_reg_phys_addr(x) (virt_to_phys((void *) CAC_ADDR( \
143#define asic_reg_addr(x) \ 111 (unsigned long) asic_reg_addr(x))))
144 ((unsigned int *) (asic_base + asic_reg_offset(x)))
145 112
146/* 113/*
147 * The asic_reg macro is gone. It should be replaced by either asic_read or 114 * The asic_reg macro is gone. It should be replaced by either asic_read or
diff --git a/arch/mips/powertv/asic/asic-calliope.c b/arch/mips/powertv/asic/asic-calliope.c
index 03d3884c6270..1ae6623444b2 100644
--- a/arch/mips/powertv/asic/asic-calliope.c
+++ b/arch/mips/powertv/asic/asic-calliope.c
@@ -23,76 +23,79 @@
23 * Description: Defines the platform resources for the SA settop. 23 * Description: Defines the platform resources for the SA settop.
24 */ 24 */
25 25
26#include <linux/init.h>
26#include <asm/mach-powertv/asic.h> 27#include <asm/mach-powertv/asic.h>
27 28
28const struct register_map calliope_register_map = { 29#define CALLIOPE_ADDR(x) (CALLIOPE_IO_BASE + (x))
29 .eic_slow0_strt_add = 0x800000,
30 .eic_cfg_bits = 0x800038,
31 .eic_ready_status = 0x80004c,
32 30
33 .chipver3 = 0xA00800, 31const struct register_map calliope_register_map __initdata = {
34 .chipver2 = 0xA00804, 32 .eic_slow0_strt_add = {.phys = CALLIOPE_ADDR(0x800000)},
35 .chipver1 = 0xA00808, 33 .eic_cfg_bits = {.phys = CALLIOPE_ADDR(0x800038)},
36 .chipver0 = 0xA0080c, 34 .eic_ready_status = {.phys = CALLIOPE_ADDR(0x80004c)},
35
36 .chipver3 = {.phys = CALLIOPE_ADDR(0xA00800)},
37 .chipver2 = {.phys = CALLIOPE_ADDR(0xA00804)},
38 .chipver1 = {.phys = CALLIOPE_ADDR(0xA00808)},
39 .chipver0 = {.phys = CALLIOPE_ADDR(0xA0080c)},
37 40
38 /* The registers of IRBlaster */ 41 /* The registers of IRBlaster */
39 .uart1_intstat = 0xA01800, 42 .uart1_intstat = {.phys = CALLIOPE_ADDR(0xA01800)},
40 .uart1_inten = 0xA01804, 43 .uart1_inten = {.phys = CALLIOPE_ADDR(0xA01804)},
41 .uart1_config1 = 0xA01808, 44 .uart1_config1 = {.phys = CALLIOPE_ADDR(0xA01808)},
42 .uart1_config2 = 0xA0180C, 45 .uart1_config2 = {.phys = CALLIOPE_ADDR(0xA0180C)},
43 .uart1_divisorhi = 0xA01810, 46 .uart1_divisorhi = {.phys = CALLIOPE_ADDR(0xA01810)},
44 .uart1_divisorlo = 0xA01814, 47 .uart1_divisorlo = {.phys = CALLIOPE_ADDR(0xA01814)},
45 .uart1_data = 0xA01818, 48 .uart1_data = {.phys = CALLIOPE_ADDR(0xA01818)},
46 .uart1_status = 0xA0181C, 49 .uart1_status = {.phys = CALLIOPE_ADDR(0xA0181C)},
47 50
48 .int_stat_3 = 0xA02800, 51 .int_stat_3 = {.phys = CALLIOPE_ADDR(0xA02800)},
49 .int_stat_2 = 0xA02804, 52 .int_stat_2 = {.phys = CALLIOPE_ADDR(0xA02804)},
50 .int_stat_1 = 0xA02808, 53 .int_stat_1 = {.phys = CALLIOPE_ADDR(0xA02808)},
51 .int_stat_0 = 0xA0280c, 54 .int_stat_0 = {.phys = CALLIOPE_ADDR(0xA0280c)},
52 .int_config = 0xA02810, 55 .int_config = {.phys = CALLIOPE_ADDR(0xA02810)},
53 .int_int_scan = 0xA02818, 56 .int_int_scan = {.phys = CALLIOPE_ADDR(0xA02818)},
54 .ien_int_3 = 0xA02830, 57 .ien_int_3 = {.phys = CALLIOPE_ADDR(0xA02830)},
55 .ien_int_2 = 0xA02834, 58 .ien_int_2 = {.phys = CALLIOPE_ADDR(0xA02834)},
56 .ien_int_1 = 0xA02838, 59 .ien_int_1 = {.phys = CALLIOPE_ADDR(0xA02838)},
57 .ien_int_0 = 0xA0283c, 60 .ien_int_0 = {.phys = CALLIOPE_ADDR(0xA0283c)},
58 .int_level_3_3 = 0xA02880, 61 .int_level_3_3 = {.phys = CALLIOPE_ADDR(0xA02880)},
59 .int_level_3_2 = 0xA02884, 62 .int_level_3_2 = {.phys = CALLIOPE_ADDR(0xA02884)},
60 .int_level_3_1 = 0xA02888, 63 .int_level_3_1 = {.phys = CALLIOPE_ADDR(0xA02888)},
61 .int_level_3_0 = 0xA0288c, 64 .int_level_3_0 = {.phys = CALLIOPE_ADDR(0xA0288c)},
62 .int_level_2_3 = 0xA02890, 65 .int_level_2_3 = {.phys = CALLIOPE_ADDR(0xA02890)},
63 .int_level_2_2 = 0xA02894, 66 .int_level_2_2 = {.phys = CALLIOPE_ADDR(0xA02894)},
64 .int_level_2_1 = 0xA02898, 67 .int_level_2_1 = {.phys = CALLIOPE_ADDR(0xA02898)},
65 .int_level_2_0 = 0xA0289c, 68 .int_level_2_0 = {.phys = CALLIOPE_ADDR(0xA0289c)},
66 .int_level_1_3 = 0xA028a0, 69 .int_level_1_3 = {.phys = CALLIOPE_ADDR(0xA028a0)},
67 .int_level_1_2 = 0xA028a4, 70 .int_level_1_2 = {.phys = CALLIOPE_ADDR(0xA028a4)},
68 .int_level_1_1 = 0xA028a8, 71 .int_level_1_1 = {.phys = CALLIOPE_ADDR(0xA028a8)},
69 .int_level_1_0 = 0xA028ac, 72 .int_level_1_0 = {.phys = CALLIOPE_ADDR(0xA028ac)},
70 .int_level_0_3 = 0xA028b0, 73 .int_level_0_3 = {.phys = CALLIOPE_ADDR(0xA028b0)},
71 .int_level_0_2 = 0xA028b4, 74 .int_level_0_2 = {.phys = CALLIOPE_ADDR(0xA028b4)},
72 .int_level_0_1 = 0xA028b8, 75 .int_level_0_1 = {.phys = CALLIOPE_ADDR(0xA028b8)},
73 .int_level_0_0 = 0xA028bc, 76 .int_level_0_0 = {.phys = CALLIOPE_ADDR(0xA028bc)},
74 .int_docsis_en = 0xA028F4, 77 .int_docsis_en = {.phys = CALLIOPE_ADDR(0xA028F4)},
75 78
76 .mips_pll_setup = 0x980000, 79 .mips_pll_setup = {.phys = CALLIOPE_ADDR(0x980000)},
77 .usb_fs = 0x980030, /* -default 72800028- */ 80 .usb_fs = {.phys = CALLIOPE_ADDR(0x980030)},
78 .test_bus = 0x9800CC, 81 .test_bus = {.phys = CALLIOPE_ADDR(0x9800CC)},
79 .crt_spare = 0x9800d4, 82 .crt_spare = {.phys = CALLIOPE_ADDR(0x9800d4)},
80 .usb2_ohci_int_mask = 0x9A000c, 83 .usb2_ohci_int_mask = {.phys = CALLIOPE_ADDR(0x9A000c)},
81 .usb2_strap = 0x9A0014, 84 .usb2_strap = {.phys = CALLIOPE_ADDR(0x9A0014)},
82 .ehci_hcapbase = 0x9BFE00, 85 .ehci_hcapbase = {.phys = CALLIOPE_ADDR(0x9BFE00)},
83 .ohci_hc_revision = 0x9BFC00, 86 .ohci_hc_revision = {.phys = CALLIOPE_ADDR(0x9BFC00)},
84 .bcm1_bs_lmi_steer = 0x9E0004, 87 .bcm1_bs_lmi_steer = {.phys = CALLIOPE_ADDR(0x9E0004)},
85 .usb2_control = 0x9E0054, 88 .usb2_control = {.phys = CALLIOPE_ADDR(0x9E0054)},
86 .usb2_stbus_obc = 0x9BFF00, 89 .usb2_stbus_obc = {.phys = CALLIOPE_ADDR(0x9BFF00)},
87 .usb2_stbus_mess_size = 0x9BFF04, 90 .usb2_stbus_mess_size = {.phys = CALLIOPE_ADDR(0x9BFF04)},
88 .usb2_stbus_chunk_size = 0x9BFF08, 91 .usb2_stbus_chunk_size = {.phys = CALLIOPE_ADDR(0x9BFF08)},
89 92
90 .pcie_regs = 0x000000, /* -doesn't exist- */ 93 .pcie_regs = {.phys = 0x000000}, /* -doesn't exist- */
91 .tim_ch = 0xA02C10, 94 .tim_ch = {.phys = CALLIOPE_ADDR(0xA02C10)},
92 .tim_cl = 0xA02C14, 95 .tim_cl = {.phys = CALLIOPE_ADDR(0xA02C14)},
93 .gpio_dout = 0xA02c20, 96 .gpio_dout = {.phys = CALLIOPE_ADDR(0xA02c20)},
94 .gpio_din = 0xA02c24, 97 .gpio_din = {.phys = CALLIOPE_ADDR(0xA02c24)},
95 .gpio_dir = 0xA02c2C, 98 .gpio_dir = {.phys = CALLIOPE_ADDR(0xA02c2C)},
96 .watchdog = 0xA02c30, 99 .watchdog = {.phys = CALLIOPE_ADDR(0xA02c30)},
97 .front_panel = 0x000000, /* -not used- */ 100 .front_panel = {.phys = 0x000000}, /* -not used- */
98}; 101};
diff --git a/arch/mips/powertv/asic/asic-cronus.c b/arch/mips/powertv/asic/asic-cronus.c
index 5f4589c9f83d..5bb64bfb508b 100644
--- a/arch/mips/powertv/asic/asic-cronus.c
+++ b/arch/mips/powertv/asic/asic-cronus.c
@@ -23,76 +23,79 @@
23 * Description: Defines the platform resources for the SA settop. 23 * Description: Defines the platform resources for the SA settop.
24 */ 24 */
25 25
26#include <linux/init.h>
26#include <asm/mach-powertv/asic.h> 27#include <asm/mach-powertv/asic.h>
27 28
28const struct register_map cronus_register_map = { 29#define CRONUS_ADDR(x) (CRONUS_IO_BASE + (x))
29 .eic_slow0_strt_add = 0x000000,
30 .eic_cfg_bits = 0x000038,
31 .eic_ready_status = 0x00004C,
32 30
33 .chipver3 = 0x2A0800, 31const struct register_map cronus_register_map __initdata = {
34 .chipver2 = 0x2A0804, 32 .eic_slow0_strt_add = {.phys = CRONUS_ADDR(0x000000)},
35 .chipver1 = 0x2A0808, 33 .eic_cfg_bits = {.phys = CRONUS_ADDR(0x000038)},
36 .chipver0 = 0x2A080C, 34 .eic_ready_status = {.phys = CRONUS_ADDR(0x00004C)},
35
36 .chipver3 = {.phys = CRONUS_ADDR(0x2A0800)},
37 .chipver2 = {.phys = CRONUS_ADDR(0x2A0804)},
38 .chipver1 = {.phys = CRONUS_ADDR(0x2A0808)},
39 .chipver0 = {.phys = CRONUS_ADDR(0x2A080C)},
37 40
38 /* The registers of IRBlaster */ 41 /* The registers of IRBlaster */
39 .uart1_intstat = 0x2A1800, 42 .uart1_intstat = {.phys = CRONUS_ADDR(0x2A1800)},
40 .uart1_inten = 0x2A1804, 43 .uart1_inten = {.phys = CRONUS_ADDR(0x2A1804)},
41 .uart1_config1 = 0x2A1808, 44 .uart1_config1 = {.phys = CRONUS_ADDR(0x2A1808)},
42 .uart1_config2 = 0x2A180C, 45 .uart1_config2 = {.phys = CRONUS_ADDR(0x2A180C)},
43 .uart1_divisorhi = 0x2A1810, 46 .uart1_divisorhi = {.phys = CRONUS_ADDR(0x2A1810)},
44 .uart1_divisorlo = 0x2A1814, 47 .uart1_divisorlo = {.phys = CRONUS_ADDR(0x2A1814)},
45 .uart1_data = 0x2A1818, 48 .uart1_data = {.phys = CRONUS_ADDR(0x2A1818)},
46 .uart1_status = 0x2A181C, 49 .uart1_status = {.phys = CRONUS_ADDR(0x2A181C)},
47 50
48 .int_stat_3 = 0x2A2800, 51 .int_stat_3 = {.phys = CRONUS_ADDR(0x2A2800)},
49 .int_stat_2 = 0x2A2804, 52 .int_stat_2 = {.phys = CRONUS_ADDR(0x2A2804)},
50 .int_stat_1 = 0x2A2808, 53 .int_stat_1 = {.phys = CRONUS_ADDR(0x2A2808)},
51 .int_stat_0 = 0x2A280C, 54 .int_stat_0 = {.phys = CRONUS_ADDR(0x2A280C)},
52 .int_config = 0x2A2810, 55 .int_config = {.phys = CRONUS_ADDR(0x2A2810)},
53 .int_int_scan = 0x2A2818, 56 .int_int_scan = {.phys = CRONUS_ADDR(0x2A2818)},
54 .ien_int_3 = 0x2A2830, 57 .ien_int_3 = {.phys = CRONUS_ADDR(0x2A2830)},
55 .ien_int_2 = 0x2A2834, 58 .ien_int_2 = {.phys = CRONUS_ADDR(0x2A2834)},
56 .ien_int_1 = 0x2A2838, 59 .ien_int_1 = {.phys = CRONUS_ADDR(0x2A2838)},
57 .ien_int_0 = 0x2A283C, 60 .ien_int_0 = {.phys = CRONUS_ADDR(0x2A283C)},
58 .int_level_3_3 = 0x2A2880, 61 .int_level_3_3 = {.phys = CRONUS_ADDR(0x2A2880)},
59 .int_level_3_2 = 0x2A2884, 62 .int_level_3_2 = {.phys = CRONUS_ADDR(0x2A2884)},
60 .int_level_3_1 = 0x2A2888, 63 .int_level_3_1 = {.phys = CRONUS_ADDR(0x2A2888)},
61 .int_level_3_0 = 0x2A288C, 64 .int_level_3_0 = {.phys = CRONUS_ADDR(0x2A288C)},
62 .int_level_2_3 = 0x2A2890, 65 .int_level_2_3 = {.phys = CRONUS_ADDR(0x2A2890)},
63 .int_level_2_2 = 0x2A2894, 66 .int_level_2_2 = {.phys = CRONUS_ADDR(0x2A2894)},
64 .int_level_2_1 = 0x2A2898, 67 .int_level_2_1 = {.phys = CRONUS_ADDR(0x2A2898)},
65 .int_level_2_0 = 0x2A289C, 68 .int_level_2_0 = {.phys = CRONUS_ADDR(0x2A289C)},
66 .int_level_1_3 = 0x2A28A0, 69 .int_level_1_3 = {.phys = CRONUS_ADDR(0x2A28A0)},
67 .int_level_1_2 = 0x2A28A4, 70 .int_level_1_2 = {.phys = CRONUS_ADDR(0x2A28A4)},
68 .int_level_1_1 = 0x2A28A8, 71 .int_level_1_1 = {.phys = CRONUS_ADDR(0x2A28A8)},
69 .int_level_1_0 = 0x2A28AC, 72 .int_level_1_0 = {.phys = CRONUS_ADDR(0x2A28AC)},
70 .int_level_0_3 = 0x2A28B0, 73 .int_level_0_3 = {.phys = CRONUS_ADDR(0x2A28B0)},
71 .int_level_0_2 = 0x2A28B4, 74 .int_level_0_2 = {.phys = CRONUS_ADDR(0x2A28B4)},
72 .int_level_0_1 = 0x2A28B8, 75 .int_level_0_1 = {.phys = CRONUS_ADDR(0x2A28B8)},
73 .int_level_0_0 = 0x2A28BC, 76 .int_level_0_0 = {.phys = CRONUS_ADDR(0x2A28BC)},
74 .int_docsis_en = 0x2A28F4, 77 .int_docsis_en = {.phys = CRONUS_ADDR(0x2A28F4)},
75 78
76 .mips_pll_setup = 0x1C0000, 79 .mips_pll_setup = {.phys = CRONUS_ADDR(0x1C0000)},
77 .usb_fs = 0x1C0018, 80 .usb_fs = {.phys = CRONUS_ADDR(0x1C0018)},
78 .test_bus = 0x1C00CC, 81 .test_bus = {.phys = CRONUS_ADDR(0x1C00CC)},
79 .crt_spare = 0x1c00d4, 82 .crt_spare = {.phys = CRONUS_ADDR(0x1c00d4)},
80 .usb2_ohci_int_mask = 0x20000C, 83 .usb2_ohci_int_mask = {.phys = CRONUS_ADDR(0x20000C)},
81 .usb2_strap = 0x200014, 84 .usb2_strap = {.phys = CRONUS_ADDR(0x200014)},
82 .ehci_hcapbase = 0x21FE00, 85 .ehci_hcapbase = {.phys = CRONUS_ADDR(0x21FE00)},
83 .ohci_hc_revision = 0x1E0000, 86 .ohci_hc_revision = {.phys = CRONUS_ADDR(0x1E0000)},
84 .bcm1_bs_lmi_steer = 0x2E0008, 87 .bcm1_bs_lmi_steer = {.phys = CRONUS_ADDR(0x2E0008)},
85 .usb2_control = 0x2E004C, 88 .usb2_control = {.phys = CRONUS_ADDR(0x2E004C)},
86 .usb2_stbus_obc = 0x21FF00, 89 .usb2_stbus_obc = {.phys = CRONUS_ADDR(0x21FF00)},
87 .usb2_stbus_mess_size = 0x21FF04, 90 .usb2_stbus_mess_size = {.phys = CRONUS_ADDR(0x21FF04)},
88 .usb2_stbus_chunk_size = 0x21FF08, 91 .usb2_stbus_chunk_size = {.phys = CRONUS_ADDR(0x21FF08)},
89 92
90 .pcie_regs = 0x220000, 93 .pcie_regs = {.phys = CRONUS_ADDR(0x220000)},
91 .tim_ch = 0x2A2C10, 94 .tim_ch = {.phys = CRONUS_ADDR(0x2A2C10)},
92 .tim_cl = 0x2A2C14, 95 .tim_cl = {.phys = CRONUS_ADDR(0x2A2C14)},
93 .gpio_dout = 0x2A2C20, 96 .gpio_dout = {.phys = CRONUS_ADDR(0x2A2C20)},
94 .gpio_din = 0x2A2C24, 97 .gpio_din = {.phys = CRONUS_ADDR(0x2A2C24)},
95 .gpio_dir = 0x2A2C2C, 98 .gpio_dir = {.phys = CRONUS_ADDR(0x2A2C2C)},
96 .watchdog = 0x2A2C30, 99 .watchdog = {.phys = CRONUS_ADDR(0x2A2C30)},
97 .front_panel = 0x2A3800, 100 .front_panel = {.phys = CRONUS_ADDR(0x2A3800)},
98}; 101};
diff --git a/arch/mips/powertv/asic/asic-zeus.c b/arch/mips/powertv/asic/asic-zeus.c
index 1469daab920e..095cbe10ebb9 100644
--- a/arch/mips/powertv/asic/asic-zeus.c
+++ b/arch/mips/powertv/asic/asic-zeus.c
@@ -23,76 +23,79 @@
23 * Description: Defines the platform resources for the SA settop. 23 * Description: Defines the platform resources for the SA settop.
24 */ 24 */
25 25
26#include <linux/init.h>
26#include <asm/mach-powertv/asic.h> 27#include <asm/mach-powertv/asic.h>
27 28
28const struct register_map zeus_register_map = { 29#define ZEUS_ADDR(x) (ZEUS_IO_BASE + (x))
29 .eic_slow0_strt_add = 0x000000,
30 .eic_cfg_bits = 0x000038,
31 .eic_ready_status = 0x00004c,
32 30
33 .chipver3 = 0x280800, 31const struct register_map zeus_register_map __initdata = {
34 .chipver2 = 0x280804, 32 .eic_slow0_strt_add = {.phys = ZEUS_ADDR(0x000000)},
35 .chipver1 = 0x280808, 33 .eic_cfg_bits = {.phys = ZEUS_ADDR(0x000038)},
36 .chipver0 = 0x28080c, 34 .eic_ready_status = {.phys = ZEUS_ADDR(0x00004c)},
35
36 .chipver3 = {.phys = ZEUS_ADDR(0x280800)},
37 .chipver2 = {.phys = ZEUS_ADDR(0x280804)},
38 .chipver1 = {.phys = ZEUS_ADDR(0x280808)},
39 .chipver0 = {.phys = ZEUS_ADDR(0x28080c)},
37 40
38 /* The registers of IRBlaster */ 41 /* The registers of IRBlaster */
39 .uart1_intstat = 0x281800, 42 .uart1_intstat = {.phys = ZEUS_ADDR(0x281800)},
40 .uart1_inten = 0x281804, 43 .uart1_inten = {.phys = ZEUS_ADDR(0x281804)},
41 .uart1_config1 = 0x281808, 44 .uart1_config1 = {.phys = ZEUS_ADDR(0x281808)},
42 .uart1_config2 = 0x28180C, 45 .uart1_config2 = {.phys = ZEUS_ADDR(0x28180C)},
43 .uart1_divisorhi = 0x281810, 46 .uart1_divisorhi = {.phys = ZEUS_ADDR(0x281810)},
44 .uart1_divisorlo = 0x281814, 47 .uart1_divisorlo = {.phys = ZEUS_ADDR(0x281814)},
45 .uart1_data = 0x281818, 48 .uart1_data = {.phys = ZEUS_ADDR(0x281818)},
46 .uart1_status = 0x28181C, 49 .uart1_status = {.phys = ZEUS_ADDR(0x28181C)},
47 50
48 .int_stat_3 = 0x282800, 51 .int_stat_3 = {.phys = ZEUS_ADDR(0x282800)},
49 .int_stat_2 = 0x282804, 52 .int_stat_2 = {.phys = ZEUS_ADDR(0x282804)},
50 .int_stat_1 = 0x282808, 53 .int_stat_1 = {.phys = ZEUS_ADDR(0x282808)},
51 .int_stat_0 = 0x28280c, 54 .int_stat_0 = {.phys = ZEUS_ADDR(0x28280c)},
52 .int_config = 0x282810, 55 .int_config = {.phys = ZEUS_ADDR(0x282810)},
53 .int_int_scan = 0x282818, 56 .int_int_scan = {.phys = ZEUS_ADDR(0x282818)},
54 .ien_int_3 = 0x282830, 57 .ien_int_3 = {.phys = ZEUS_ADDR(0x282830)},
55 .ien_int_2 = 0x282834, 58 .ien_int_2 = {.phys = ZEUS_ADDR(0x282834)},
56 .ien_int_1 = 0x282838, 59 .ien_int_1 = {.phys = ZEUS_ADDR(0x282838)},
57 .ien_int_0 = 0x28283c, 60 .ien_int_0 = {.phys = ZEUS_ADDR(0x28283c)},
58 .int_level_3_3 = 0x282880, 61 .int_level_3_3 = {.phys = ZEUS_ADDR(0x282880)},
59 .int_level_3_2 = 0x282884, 62 .int_level_3_2 = {.phys = ZEUS_ADDR(0x282884)},
60 .int_level_3_1 = 0x282888, 63 .int_level_3_1 = {.phys = ZEUS_ADDR(0x282888)},
61 .int_level_3_0 = 0x28288c, 64 .int_level_3_0 = {.phys = ZEUS_ADDR(0x28288c)},
62 .int_level_2_3 = 0x282890, 65 .int_level_2_3 = {.phys = ZEUS_ADDR(0x282890)},
63 .int_level_2_2 = 0x282894, 66 .int_level_2_2 = {.phys = ZEUS_ADDR(0x282894)},
64 .int_level_2_1 = 0x282898, 67 .int_level_2_1 = {.phys = ZEUS_ADDR(0x282898)},
65 .int_level_2_0 = 0x28289c, 68 .int_level_2_0 = {.phys = ZEUS_ADDR(0x28289c)},
66 .int_level_1_3 = 0x2828a0, 69 .int_level_1_3 = {.phys = ZEUS_ADDR(0x2828a0)},
67 .int_level_1_2 = 0x2828a4, 70 .int_level_1_2 = {.phys = ZEUS_ADDR(0x2828a4)},
68 .int_level_1_1 = 0x2828a8, 71 .int_level_1_1 = {.phys = ZEUS_ADDR(0x2828a8)},
69 .int_level_1_0 = 0x2828ac, 72 .int_level_1_0 = {.phys = ZEUS_ADDR(0x2828ac)},
70 .int_level_0_3 = 0x2828b0, 73 .int_level_0_3 = {.phys = ZEUS_ADDR(0x2828b0)},
71 .int_level_0_2 = 0x2828b4, 74 .int_level_0_2 = {.phys = ZEUS_ADDR(0x2828b4)},
72 .int_level_0_1 = 0x2828b8, 75 .int_level_0_1 = {.phys = ZEUS_ADDR(0x2828b8)},
73 .int_level_0_0 = 0x2828bc, 76 .int_level_0_0 = {.phys = ZEUS_ADDR(0x2828bc)},
74 .int_docsis_en = 0x2828F4, 77 .int_docsis_en = {.phys = ZEUS_ADDR(0x2828F4)},
75 78
76 .mips_pll_setup = 0x1a0000, 79 .mips_pll_setup = {.phys = ZEUS_ADDR(0x1a0000)},
77 .usb_fs = 0x1a0018, 80 .usb_fs = {.phys = ZEUS_ADDR(0x1a0018)},
78 .test_bus = 0x1a0238, 81 .test_bus = {.phys = ZEUS_ADDR(0x1a0238)},
79 .crt_spare = 0x1a0090, 82 .crt_spare = {.phys = ZEUS_ADDR(0x1a0090)},
80 .usb2_ohci_int_mask = 0x1e000c, 83 .usb2_ohci_int_mask = {.phys = ZEUS_ADDR(0x1e000c)},
81 .usb2_strap = 0x1e0014, 84 .usb2_strap = {.phys = ZEUS_ADDR(0x1e0014)},
82 .ehci_hcapbase = 0x1FFE00, 85 .ehci_hcapbase = {.phys = ZEUS_ADDR(0x1FFE00)},
83 .ohci_hc_revision = 0x1FFC00, 86 .ohci_hc_revision = {.phys = ZEUS_ADDR(0x1FFC00)},
84 .bcm1_bs_lmi_steer = 0x2C0008, 87 .bcm1_bs_lmi_steer = {.phys = ZEUS_ADDR(0x2C0008)},
85 .usb2_control = 0x2c01a0, 88 .usb2_control = {.phys = ZEUS_ADDR(0x2c01a0)},
86 .usb2_stbus_obc = 0x1FFF00, 89 .usb2_stbus_obc = {.phys = ZEUS_ADDR(0x1FFF00)},
87 .usb2_stbus_mess_size = 0x1FFF04, 90 .usb2_stbus_mess_size = {.phys = ZEUS_ADDR(0x1FFF04)},
88 .usb2_stbus_chunk_size = 0x1FFF08, 91 .usb2_stbus_chunk_size = {.phys = ZEUS_ADDR(0x1FFF08)},
89 92
90 .pcie_regs = 0x200000, 93 .pcie_regs = {.phys = ZEUS_ADDR(0x200000)},
91 .tim_ch = 0x282C10, 94 .tim_ch = {.phys = ZEUS_ADDR(0x282C10)},
92 .tim_cl = 0x282C14, 95 .tim_cl = {.phys = ZEUS_ADDR(0x282C14)},
93 .gpio_dout = 0x282c20, 96 .gpio_dout = {.phys = ZEUS_ADDR(0x282c20)},
94 .gpio_din = 0x282c24, 97 .gpio_din = {.phys = ZEUS_ADDR(0x282c24)},
95 .gpio_dir = 0x282c2C, 98 .gpio_dir = {.phys = ZEUS_ADDR(0x282c2C)},
96 .watchdog = 0x282c30, 99 .watchdog = {.phys = ZEUS_ADDR(0x282c30)},
97 .front_panel = 0x283800, 100 .front_panel = {.phys = ZEUS_ADDR(0x283800)},
98}; 101};
diff --git a/arch/mips/powertv/asic/asic_devices.c b/arch/mips/powertv/asic/asic_devices.c
index bae82880b6b5..6a882194e063 100644
--- a/arch/mips/powertv/asic/asic_devices.c
+++ b/arch/mips/powertv/asic/asic_devices.c
@@ -67,8 +67,8 @@ enum asic_type asic;
67 67
68unsigned int platform_features; 68unsigned int platform_features;
69unsigned int platform_family; 69unsigned int platform_family;
70const struct register_map *register_map; 70struct register_map _asic_register_map;
71EXPORT_SYMBOL(register_map); /* Exported for testing */ 71EXPORT_SYMBOL(_asic_register_map); /* Exported for testing */
72unsigned long asic_phy_base; 72unsigned long asic_phy_base;
73unsigned long asic_base; 73unsigned long asic_base;
74EXPORT_SYMBOL(asic_base); /* Exported for testing */ 74EXPORT_SYMBOL(asic_base); /* Exported for testing */
@@ -418,6 +418,15 @@ void platform_unconfigure_usb_ohci()
418{ 418{
419} 419}
420 420
421static void __init set_register_map(unsigned long phys_base,
422 const struct register_map *map)
423{
424 asic_phy_base = phys_base;
425 _asic_register_map = *map;
426 register_map_virtualize(&_asic_register_map);
427 asic_base = (unsigned long)ioremap_nocache(phys_base, ASIC_IO_SIZE);
428}
429
421/** 430/**
422 * configure_platform - configuration based on platform type. 431 * configure_platform - configuration based on platform type.
423 */ 432 */
@@ -431,10 +440,7 @@ void __init configure_platform(void)
431 case FAMILY_1500VZF: 440 case FAMILY_1500VZF:
432 platform_features = FFS_CAPABLE; 441 platform_features = FFS_CAPABLE;
433 asic = ASIC_CALLIOPE; 442 asic = ASIC_CALLIOPE;
434 asic_phy_base = CALLIOPE_IO_BASE; 443 set_register_map(CALLIOPE_IO_BASE, &calliope_register_map);
435 register_map = &calliope_register_map;
436 asic_base = (unsigned long)ioremap_nocache(asic_phy_base,
437 ASIC_IO_SIZE);
438 444
439 if (platform_family == FAMILY_1500VZE) { 445 if (platform_family == FAMILY_1500VZE) {
440 gp_resources = non_dvr_vze_calliope_resources; 446 gp_resources = non_dvr_vze_calliope_resources;
@@ -455,10 +461,7 @@ void __init configure_platform(void)
455 platform_features = FFS_CAPABLE | PCIE_CAPABLE | 461 platform_features = FFS_CAPABLE | PCIE_CAPABLE |
456 DISPLAY_CAPABLE; 462 DISPLAY_CAPABLE;
457 asic = ASIC_ZEUS; 463 asic = ASIC_ZEUS;
458 asic_phy_base = ZEUS_IO_BASE; 464 set_register_map(ZEUS_IO_BASE, &zeus_register_map);
459 register_map = &zeus_register_map;
460 asic_base = (unsigned long)ioremap_nocache(asic_phy_base,
461 ASIC_IO_SIZE);
462 gp_resources = non_dvr_zeus_resources; 465 gp_resources = non_dvr_zeus_resources;
463 466
464 pr_info("Platform: 4500 - ZEUS, NON_DVR_CAPABLE\n"); 467 pr_info("Platform: 4500 - ZEUS, NON_DVR_CAPABLE\n");
@@ -471,11 +474,6 @@ void __init configure_platform(void)
471 /* The settop has PCIE but it isn't used, so don't advertise 474 /* The settop has PCIE but it isn't used, so don't advertise
472 * it*/ 475 * it*/
473 platform_features = FFS_CAPABLE | DISPLAY_CAPABLE; 476 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,
477 ASIC_IO_SIZE);
478 gp_resources = non_dvr_cronuslite_resources;
479 477
480 /* ASIC version will determine if this is a real CronusLite or 478 /* ASIC version will determine if this is a real CronusLite or
481 * Castrati(Cronus) */ 479 * Castrati(Cronus) */
@@ -489,6 +487,9 @@ void __init configure_platform(void)
489 else 487 else
490 asic = ASIC_CRONUSLITE; 488 asic = ASIC_CRONUSLITE;
491 489
490 /* Cronus and Cronus Lite have the same register map */
491 set_register_map(CRONUS_IO_BASE, &cronus_register_map);
492 gp_resources = non_dvr_cronuslite_resources;
492 pr_info("Platform: 4600 - %s, NON_DVR_CAPABLE, " 493 pr_info("Platform: 4600 - %s, NON_DVR_CAPABLE, "
493 "chipversion=0x%08X\n", 494 "chipversion=0x%08X\n",
494 (asic == ASIC_CRONUS) ? "CRONUS" : "CRONUS LITE", 495 (asic == ASIC_CRONUS) ? "CRONUS" : "CRONUS LITE",
@@ -498,10 +499,7 @@ void __init configure_platform(void)
498 case FAMILY_4600VZA: 499 case FAMILY_4600VZA:
499 platform_features = FFS_CAPABLE | DISPLAY_CAPABLE; 500 platform_features = FFS_CAPABLE | DISPLAY_CAPABLE;
500 asic = ASIC_CRONUS; 501 asic = ASIC_CRONUS;
501 asic_phy_base = CRONUS_IO_BASE; 502 set_register_map(CRONUS_IO_BASE, &cronus_register_map);
502 register_map = &cronus_register_map;
503 asic_base = (unsigned long)ioremap_nocache(asic_phy_base,
504 ASIC_IO_SIZE);
505 gp_resources = non_dvr_cronus_resources; 503 gp_resources = non_dvr_cronus_resources;
506 504
507 pr_info("Platform: Vz Class A - CRONUS, NON_DVR_CAPABLE\n"); 505 pr_info("Platform: Vz Class A - CRONUS, NON_DVR_CAPABLE\n");
@@ -512,10 +510,7 @@ void __init configure_platform(void)
512 platform_features = DVR_CAPABLE | PCIE_CAPABLE | 510 platform_features = DVR_CAPABLE | PCIE_CAPABLE |
513 DISPLAY_CAPABLE; 511 DISPLAY_CAPABLE;
514 asic = ASIC_ZEUS; 512 asic = ASIC_ZEUS;
515 asic_phy_base = ZEUS_IO_BASE; 513 set_register_map(ZEUS_IO_BASE, &zeus_register_map);
516 register_map = &zeus_register_map;
517 asic_base = (unsigned long)ioremap_nocache(asic_phy_base,
518 ASIC_IO_SIZE);
519 gp_resources = dvr_zeus_resources; 514 gp_resources = dvr_zeus_resources;
520 515
521 pr_info("Platform: 8500/RNG200 - ZEUS, DVR_CAPABLE\n"); 516 pr_info("Platform: 8500/RNG200 - ZEUS, DVR_CAPABLE\n");
@@ -526,10 +521,7 @@ void __init configure_platform(void)
526 platform_features = DVR_CAPABLE | PCIE_CAPABLE | 521 platform_features = DVR_CAPABLE | PCIE_CAPABLE |
527 DISPLAY_CAPABLE; 522 DISPLAY_CAPABLE;
528 asic = ASIC_CRONUS; 523 asic = ASIC_CRONUS;
529 asic_phy_base = CRONUS_IO_BASE; 524 set_register_map(CRONUS_IO_BASE, &cronus_register_map);
530 register_map = &cronus_register_map;
531 asic_base = (unsigned long)ioremap_nocache(asic_phy_base,
532 ASIC_IO_SIZE);
533 gp_resources = dvr_cronus_resources; 525 gp_resources = dvr_cronus_resources;
534 526
535 pr_info("Platform: 8600/Vz Class B - CRONUS, " 527 pr_info("Platform: 8600/Vz Class B - CRONUS, "