aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorGeoff Levand <geoffrey.levand@am.sony.com>2006-11-22 18:46:58 -0500
committerPaul Mackerras <paulus@samba.org>2006-12-04 04:40:54 -0500
commit00a3e2e93cd3ce73ab2d200fff22a62548da06d6 (patch)
treed52c96626676ab78598949bb6e35726a9e83da78 /arch/powerpc
parent261efc3f178c8c5b55d76208aee1f39ce247f723 (diff)
[POWERPC] ps3: add OS params support
Adds support for early access to the parameter data from the PS3 'Other OS' flash memory area. The parameter data mainly holds user preferences like static ip address. Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com> Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/platforms/ps3/Makefile2
-rw-r--r--arch/powerpc/platforms/ps3/os-area.c259
2 files changed, 260 insertions, 1 deletions
diff --git a/arch/powerpc/platforms/ps3/Makefile b/arch/powerpc/platforms/ps3/Makefile
index 8d6c72c6ea7a..6eb697786367 100644
--- a/arch/powerpc/platforms/ps3/Makefile
+++ b/arch/powerpc/platforms/ps3/Makefile
@@ -1,2 +1,2 @@
1obj-y += setup.o mm.o smp.o time.o hvcall.o htab.o repository.o 1obj-y += setup.o mm.o smp.o time.o hvcall.o htab.o repository.o
2obj-y += interrupt.o exports.o 2obj-y += interrupt.o exports.o os-area.o
diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c
new file mode 100644
index 000000000000..58358305dc10
--- /dev/null
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -0,0 +1,259 @@
1/*
2 * PS3 'Other OS' area data.
3 *
4 * Copyright (C) 2006 Sony Computer Entertainment Inc.
5 * Copyright 2006 Sony Corp.
6 *
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; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <linux/kernel.h>
22#include <linux/io.h>
23
24#include <asm/lmb.h>
25#include <asm/ps3.h>
26
27#include "platform.h"
28
29enum {
30 OS_AREA_SEGMENT_SIZE = 0X200,
31};
32
33enum {
34 HEADER_LDR_FORMAT_RAW = 0,
35 HEADER_LDR_FORMAT_GZIP = 1,
36};
37
38/**
39 * struct os_area_header - os area header segment.
40 * @magic_num: Always 'cell_ext_os_area'.
41 * @hdr_version: Header format version number.
42 * @os_area_offset: Starting segment number of os image area.
43 * @ldr_area_offset: Starting segment number of bootloader image area.
44 * @ldr_format: HEADER_LDR_FORMAT flag.
45 * @ldr_size: Size of bootloader image in bytes.
46 *
47 * Note that the docs refer to area offsets. These are offsets in units of
48 * segments from the start of the os area (top of the header). These are
49 * better thought of as segment numbers. The os area of the os area is
50 * reserved for the os image.
51 */
52
53struct os_area_header {
54 s8 magic_num[16];
55 u32 hdr_version;
56 u32 os_area_offset;
57 u32 ldr_area_offset;
58 u32 _reserved_1;
59 u32 ldr_format;
60 u32 ldr_size;
61 u32 _reserved_2[6];
62} __attribute__ ((packed));
63
64enum {
65 PARAM_BOOT_FLAG_GAME_OS = 0,
66 PARAM_BOOT_FLAG_OTHER_OS = 1,
67};
68
69enum {
70 PARAM_AV_MULTI_OUT_NTSC = 0,
71 PARAM_AV_MULTI_OUT_PAL_RGB = 1,
72 PARAM_AV_MULTI_OUT_PAL_YCBCR = 2,
73 PARAM_AV_MULTI_OUT_SECAM = 3,
74};
75
76enum {
77 PARAM_CTRL_BUTTON_O_IS_YES = 0,
78 PARAM_CTRL_BUTTON_X_IS_YES = 1,
79};
80
81/**
82 * struct os_area_params - os area params segment.
83 * @boot_flag: User preference of operating system, PARAM_BOOT_FLAG flag.
84 * @num_params: Number of params in this (params) segment.
85 * @rtc_diff: Difference in seconds between 1970 and the ps3 rtc value.
86 * @av_multi_out: User preference of AV output, PARAM_AV_MULTI_OUT flag.
87 * @ctrl_button: User preference of controller button config, PARAM_CTRL_BUTTON
88 * flag.
89 * @static_ip_addr: User preference of static IP address.
90 * @network_mask: User preference of static network mask.
91 * @default_gateway: User preference of static default gateway.
92 * @dns_primary: User preference of static primary dns server.
93 * @dns_secondary: User preference of static secondary dns server.
94 *
95 * User preference of zero for static_ip_addr means use dhcp.
96 */
97
98struct os_area_params {
99 u32 boot_flag;
100 u32 _reserved_1[3];
101 u32 num_params;
102 u32 _reserved_2[3];
103 /* param 0 */
104 s64 rtc_diff;
105 u8 av_multi_out;
106 u8 ctrl_button;
107 u8 _reserved_3[6];
108 /* param 1 */
109 u8 static_ip_addr[4];
110 u8 network_mask[4];
111 u8 default_gateway[4];
112 u8 _reserved_4[4];
113 /* param 2 */
114 u8 dns_primary[4];
115 u8 dns_secondary[4];
116 u8 _reserved_5[8];
117} __attribute__ ((packed));
118
119/**
120 * struct saved_params - Static working copies of data from the 'Other OS' area.
121 *
122 * For the convinience of the guest, the HV makes a copy of the 'Other OS' area
123 * in flash to a high address in the boot memory region and then puts that RAM
124 * address and the byte count into the repository for retreval by the guest.
125 * We copy the data we want into a static variable and allow the memory setup
126 * by the HV to be claimed by the lmb manager.
127 */
128
129struct saved_params {
130 /* param 0 */
131 s64 rtc_diff;
132 unsigned int av_multi_out;
133 unsigned int ctrl_button;
134 /* param 1 */
135 u8 static_ip_addr[4];
136 u8 network_mask[4];
137 u8 default_gateway[4];
138 /* param 2 */
139 u8 dns_primary[4];
140 u8 dns_secondary[4];
141} static saved_params;
142
143#define dump_header(_a) _dump_header(_a, __func__, __LINE__)
144static void _dump_header(const struct os_area_header __iomem *h, const char* func,
145 int line)
146{
147 pr_debug("%s:%d: h.magic_num: '%s'\n", func, line,
148 h->magic_num);
149 pr_debug("%s:%d: h.hdr_version: %u\n", func, line,
150 h->hdr_version);
151 pr_debug("%s:%d: h.os_area_offset: %u\n", func, line,
152 h->os_area_offset);
153 pr_debug("%s:%d: h.ldr_area_offset: %u\n", func, line,
154 h->ldr_area_offset);
155 pr_debug("%s:%d: h.ldr_format: %u\n", func, line,
156 h->ldr_format);
157 pr_debug("%s:%d: h.ldr_size: %xh\n", func, line,
158 h->ldr_size);
159}
160
161#define dump_params(_a) _dump_params(_a, __func__, __LINE__)
162static void _dump_params(const struct os_area_params __iomem *p, const char* func,
163 int line)
164{
165 pr_debug("%s:%d: p.boot_flag: %u\n", func, line, p->boot_flag);
166 pr_debug("%s:%d: p.num_params: %u\n", func, line, p->num_params);
167 pr_debug("%s:%d: p.rtc_diff %ld\n", func, line, p->rtc_diff);
168 pr_debug("%s:%d: p.av_multi_out %u\n", func, line, p->av_multi_out);
169 pr_debug("%s:%d: p.ctrl_button: %u\n", func, line, p->ctrl_button);
170 pr_debug("%s:%d: p.static_ip_addr: %u.%u.%u.%u\n", func, line,
171 p->static_ip_addr[0], p->static_ip_addr[1],
172 p->static_ip_addr[2], p->static_ip_addr[3]);
173 pr_debug("%s:%d: p.network_mask: %u.%u.%u.%u\n", func, line,
174 p->network_mask[0], p->network_mask[1],
175 p->network_mask[2], p->network_mask[3]);
176 pr_debug("%s:%d: p.default_gateway: %u.%u.%u.%u\n", func, line,
177 p->default_gateway[0], p->default_gateway[1],
178 p->default_gateway[2], p->default_gateway[3]);
179 pr_debug("%s:%d: p.dns_primary: %u.%u.%u.%u\n", func, line,
180 p->dns_primary[0], p->dns_primary[1],
181 p->dns_primary[2], p->dns_primary[3]);
182 pr_debug("%s:%d: p.dns_secondary: %u.%u.%u.%u\n", func, line,
183 p->dns_secondary[0], p->dns_secondary[1],
184 p->dns_secondary[2], p->dns_secondary[3]);
185}
186
187static int __init verify_header(const struct os_area_header *header)
188{
189 if (memcmp(header->magic_num, "cell_ext_os_area", 16)) {
190 pr_debug("%s:%d magic_num failed\n", __func__, __LINE__);
191 return -1;
192 }
193
194 if (header->hdr_version < 1) {
195 pr_debug("%s:%d hdr_version failed\n", __func__, __LINE__);
196 return -1;
197 }
198
199 if (header->os_area_offset > header->ldr_area_offset) {
200 pr_debug("%s:%d offsets failed\n", __func__, __LINE__);
201 return -1;
202 }
203
204 return 0;
205}
206
207int __init ps3_os_area_init(void)
208{
209 int result;
210 u64 lpar_addr;
211 unsigned int size;
212 struct os_area_header *header;
213 struct os_area_params *params;
214
215 result = ps3_repository_read_boot_dat_info(&lpar_addr, &size);
216
217 if (result) {
218 pr_debug("%s:%d ps3_repository_read_boot_dat_info failed\n",
219 __func__, __LINE__);
220 return result;
221 }
222
223 header = (struct os_area_header *)__va(lpar_addr);
224 params = (struct os_area_params *)__va(lpar_addr + OS_AREA_SEGMENT_SIZE);
225
226 result = verify_header(header);
227
228 if (result) {
229 pr_debug("%s:%d verify_header failed\n", __func__, __LINE__);
230 dump_header(header);
231 return -EIO;
232 }
233
234 dump_header(header);
235 dump_params(params);
236
237 saved_params.rtc_diff = params->rtc_diff;
238 saved_params.av_multi_out = params->av_multi_out;
239 saved_params.ctrl_button = params->ctrl_button;
240 memcpy(saved_params.static_ip_addr, params->static_ip_addr, 4);
241 memcpy(saved_params.network_mask, params->network_mask, 4);
242 memcpy(saved_params.default_gateway, params->default_gateway, 4);
243 memcpy(saved_params.dns_secondary, params->dns_secondary, 4);
244
245 return result;
246}
247
248/**
249 * ps3_os_area_rtc_diff - Returns the ps3 rtc diff value.
250 *
251 * The ps3 rtc maintains a value that approximates seconds since
252 * 2000-01-01 00:00:00 UTC. Returns the exact number of seconds from 1970 to
253 * 2000 when saved_params.rtc_diff has not been properly set up.
254 */
255
256u64 ps3_os_area_rtc_diff(void)
257{
258 return saved_params.rtc_diff ? saved_params.rtc_diff : 946684800UL;
259}