Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * linux/arch/arm/boot/compressed/ofw-shark.c |
| 3 | * |
| 4 | * by Alexander Schulz |
| 5 | * |
| 6 | * This file is used to get some basic information |
| 7 | * about the memory layout of the shark we are running |
| 8 | * on. Memory is usually divided in blocks a 8 MB. |
| 9 | * And bootargs are copied from OpenFirmware. |
| 10 | */ |
| 11 | |
| 12 | |
| 13 | #include <linux/kernel.h> |
| 14 | #include <linux/types.h> |
| 15 | #include <asm/setup.h> |
| 16 | #include <asm/page.h> |
| 17 | |
| 18 | |
| 19 | asmlinkage void |
| 20 | create_params (unsigned long *buffer) |
| 21 | { |
| 22 | /* Is there a better address? Also change in mach-shark/core.c */ |
| 23 | struct tag *tag = (struct tag *) 0x08003000; |
| 24 | int j,i,m,k,nr_banks,size; |
| 25 | unsigned char *c; |
| 26 | |
| 27 | k = 0; |
| 28 | |
| 29 | /* Head of the taglist */ |
| 30 | tag->hdr.tag = ATAG_CORE; |
| 31 | tag->hdr.size = tag_size(tag_core); |
| 32 | tag->u.core.flags = 1; |
| 33 | tag->u.core.pagesize = PAGE_SIZE; |
| 34 | tag->u.core.rootdev = 0; |
| 35 | |
| 36 | /* Build up one tagged block for each memory region */ |
| 37 | size=0; |
| 38 | nr_banks=(unsigned int) buffer[0]; |
| 39 | for (j=0;j<nr_banks;j++){ |
| 40 | /* search the lowest address and put it into the next entry */ |
| 41 | /* not a fast sort algorithm, but there are at most 8 entries */ |
| 42 | /* and this is used only once anyway */ |
| 43 | m=0xffffffff; |
| 44 | for (i=0;i<(unsigned int) buffer[0];i++){ |
| 45 | if (buffer[2*i+1]<m) { |
| 46 | m=buffer[2*i+1]; |
| 47 | k=i; |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | tag = tag_next(tag); |
| 52 | tag->hdr.tag = ATAG_MEM; |
| 53 | tag->hdr.size = tag_size(tag_mem32); |
| 54 | tag->u.mem.size = buffer[2*k+2]; |
| 55 | tag->u.mem.start = buffer[2*k+1]; |
| 56 | |
| 57 | size += buffer[2*k+2]; |
| 58 | |
| 59 | buffer[2*k+1]=0xffffffff; /* mark as copied */ |
| 60 | } |
| 61 | |
| 62 | /* The command line */ |
| 63 | tag = tag_next(tag); |
| 64 | tag->hdr.tag = ATAG_CMDLINE; |
| 65 | |
| 66 | c=(unsigned char *)(&buffer[34]); |
| 67 | j=0; |
| 68 | while (*c) tag->u.cmdline.cmdline[j++]=*c++; |
| 69 | |
| 70 | tag->u.cmdline.cmdline[j]=0; |
| 71 | tag->hdr.size = (j + 7 + sizeof(struct tag_header)) >> 2; |
| 72 | |
| 73 | /* Hardware revision */ |
| 74 | tag = tag_next(tag); |
| 75 | tag->hdr.tag = ATAG_REVISION; |
| 76 | tag->hdr.size = tag_size(tag_revision); |
| 77 | tag->u.revision.rev = ((unsigned char) buffer[33])-'0'; |
| 78 | |
| 79 | /* End of the taglist */ |
| 80 | tag = tag_next(tag); |
| 81 | tag->hdr.tag = 0; |
| 82 | tag->hdr.size = 0; |
| 83 | } |
| 84 | |
| 85 | |
| 86 | typedef int (*ofw_handle_t)(void *); |
| 87 | |
| 88 | /* Everything below is called with a wrong MMU setting. |
| 89 | * This means: no string constants, no initialization of |
| 90 | * arrays, no global variables! This is ugly but I didn't |
| 91 | * want to write this in assembler :-) |
| 92 | */ |
| 93 | |
| 94 | int |
| 95 | of_decode_int(const unsigned char *p) |
| 96 | { |
| 97 | unsigned int i = *p++ << 8; |
| 98 | i = (i + *p++) << 8; |
| 99 | i = (i + *p++) << 8; |
| 100 | return (i + *p); |
| 101 | } |
| 102 | |
| 103 | int |
| 104 | OF_finddevice(ofw_handle_t openfirmware, char *name) |
| 105 | { |
| 106 | unsigned int args[8]; |
| 107 | char service[12]; |
| 108 | |
| 109 | service[0]='f'; |
| 110 | service[1]='i'; |
| 111 | service[2]='n'; |
| 112 | service[3]='d'; |
| 113 | service[4]='d'; |
| 114 | service[5]='e'; |
| 115 | service[6]='v'; |
| 116 | service[7]='i'; |
| 117 | service[8]='c'; |
| 118 | service[9]='e'; |
| 119 | service[10]='\0'; |
| 120 | |
| 121 | args[0]=(unsigned int)service; |
| 122 | args[1]=1; |
| 123 | args[2]=1; |
| 124 | args[3]=(unsigned int)name; |
| 125 | |
| 126 | if (openfirmware(args) == -1) |
| 127 | return -1; |
| 128 | return args[4]; |
| 129 | } |
| 130 | |
| 131 | int |
| 132 | OF_getproplen(ofw_handle_t openfirmware, int handle, char *prop) |
| 133 | { |
| 134 | unsigned int args[8]; |
| 135 | char service[12]; |
| 136 | |
| 137 | service[0]='g'; |
| 138 | service[1]='e'; |
| 139 | service[2]='t'; |
| 140 | service[3]='p'; |
| 141 | service[4]='r'; |
| 142 | service[5]='o'; |
| 143 | service[6]='p'; |
| 144 | service[7]='l'; |
| 145 | service[8]='e'; |
| 146 | service[9]='n'; |
| 147 | service[10]='\0'; |
| 148 | |
| 149 | args[0] = (unsigned int)service; |
| 150 | args[1] = 2; |
| 151 | args[2] = 1; |
| 152 | args[3] = (unsigned int)handle; |
| 153 | args[4] = (unsigned int)prop; |
| 154 | |
| 155 | if (openfirmware(args) == -1) |
| 156 | return -1; |
| 157 | return args[5]; |
| 158 | } |
| 159 | |
| 160 | int |
| 161 | OF_getprop(ofw_handle_t openfirmware, int handle, char *prop, void *buf, unsigned int buflen) |
| 162 | { |
| 163 | unsigned int args[8]; |
| 164 | char service[8]; |
| 165 | |
| 166 | service[0]='g'; |
| 167 | service[1]='e'; |
| 168 | service[2]='t'; |
| 169 | service[3]='p'; |
| 170 | service[4]='r'; |
| 171 | service[5]='o'; |
| 172 | service[6]='p'; |
| 173 | service[7]='\0'; |
| 174 | |
| 175 | args[0] = (unsigned int)service; |
| 176 | args[1] = 4; |
| 177 | args[2] = 1; |
| 178 | args[3] = (unsigned int)handle; |
| 179 | args[4] = (unsigned int)prop; |
| 180 | args[5] = (unsigned int)buf; |
| 181 | args[6] = buflen; |
| 182 | |
| 183 | if (openfirmware(args) == -1) |
| 184 | return -1; |
| 185 | return args[7]; |
| 186 | } |
| 187 | |
| 188 | asmlinkage void ofw_init(ofw_handle_t o, int *nomr, int *pointer) |
| 189 | { |
| 190 | int phandle,i,mem_len,buffer[32]; |
| 191 | char temp[15]; |
| 192 | |
| 193 | temp[0]='/'; |
| 194 | temp[1]='m'; |
| 195 | temp[2]='e'; |
| 196 | temp[3]='m'; |
| 197 | temp[4]='o'; |
| 198 | temp[5]='r'; |
| 199 | temp[6]='y'; |
| 200 | temp[7]='\0'; |
| 201 | |
| 202 | phandle=OF_finddevice(o,temp); |
| 203 | |
| 204 | temp[0]='r'; |
| 205 | temp[1]='e'; |
| 206 | temp[2]='g'; |
| 207 | temp[3]='\0'; |
| 208 | |
| 209 | mem_len = OF_getproplen(o,phandle, temp); |
| 210 | OF_getprop(o,phandle, temp, buffer, mem_len); |
| 211 | *nomr=mem_len >> 3; |
| 212 | |
| 213 | for (i=0; i<=mem_len/4; i++) pointer[i]=of_decode_int((const unsigned char *)&buffer[i]); |
| 214 | |
| 215 | temp[0]='/'; |
| 216 | temp[1]='c'; |
| 217 | temp[2]='h'; |
| 218 | temp[3]='o'; |
| 219 | temp[4]='s'; |
| 220 | temp[5]='e'; |
| 221 | temp[6]='n'; |
| 222 | temp[7]='\0'; |
| 223 | |
| 224 | phandle=OF_finddevice(o,temp); |
| 225 | |
| 226 | temp[0]='b'; |
| 227 | temp[1]='o'; |
| 228 | temp[2]='o'; |
| 229 | temp[3]='t'; |
| 230 | temp[4]='a'; |
| 231 | temp[5]='r'; |
| 232 | temp[6]='g'; |
| 233 | temp[7]='s'; |
| 234 | temp[8]='\0'; |
| 235 | |
| 236 | mem_len = OF_getproplen(o,phandle, temp); |
| 237 | OF_getprop(o,phandle, temp, buffer, mem_len); |
| 238 | if (mem_len > 128) mem_len=128; |
| 239 | for (i=0; i<=mem_len/4; i++) pointer[i+33]=buffer[i]; |
| 240 | pointer[i+33]=0; |
| 241 | |
| 242 | temp[0]='/'; |
| 243 | temp[1]='\0'; |
| 244 | phandle=OF_finddevice(o,temp); |
| 245 | temp[0]='b'; |
| 246 | temp[1]='a'; |
| 247 | temp[2]='n'; |
| 248 | temp[3]='n'; |
| 249 | temp[4]='e'; |
| 250 | temp[5]='r'; |
| 251 | temp[6]='-'; |
| 252 | temp[7]='n'; |
| 253 | temp[8]='a'; |
| 254 | temp[9]='m'; |
| 255 | temp[10]='e'; |
| 256 | temp[11]='\0'; |
| 257 | mem_len = OF_getproplen(o,phandle, temp); |
| 258 | OF_getprop(o,phandle, temp, buffer, mem_len); |
Vincent Sanders | 58dd48a | 2005-09-20 16:21:42 +0100 | [diff] [blame] | 259 | * ((unsigned char *) &pointer[32]) = ((unsigned char *) buffer)[mem_len-2]; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 260 | } |