pmac_nvram.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:9k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * BK Id: SCCS/s.pmac_nvram.c 1.17 12/01/01 20:09:06 benh
  3.  */
  4. /*
  5.  * Miscellaneous procedures for dealing with the PowerMac hardware.
  6.  */
  7. #include <linux/config.h>
  8. #include <linux/module.h>
  9. #include <linux/kernel.h>
  10. #include <linux/stddef.h>
  11. #include <linux/nvram.h>
  12. #include <linux/init.h>
  13. #include <linux/slab.h>
  14. #include <linux/delay.h>
  15. #include <asm/sections.h>
  16. #include <asm/io.h>
  17. #include <asm/system.h>
  18. #include <asm/prom.h>
  19. #include <asm/machdep.h>
  20. #include <asm/nvram.h>
  21. #include <linux/adb.h>
  22. #include <linux/pmu.h>
  23. #undef DEBUG
  24. #define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */
  25. #define CORE99_SIGNATURE 0x5a
  26. #define CORE99_ADLER_START 0x14
  27. /* Core99 nvram is a flash */
  28. #define CORE99_FLASH_STATUS_DONE 0x80
  29. #define CORE99_FLASH_STATUS_ERR 0x38
  30. #define CORE99_FLASH_CMD_ERASE_CONFIRM 0xd0
  31. #define CORE99_FLASH_CMD_ERASE_SETUP 0x20
  32. #define CORE99_FLASH_CMD_RESET 0xff
  33. #define CORE99_FLASH_CMD_WRITE_SETUP 0x40
  34. /* CHRP NVRAM header */
  35. struct chrp_header {
  36.   u8 signature;
  37.   u8 cksum;
  38.   u16 len;
  39.   char          name[12];
  40.   u8 data[0];
  41. };
  42. struct core99_header {
  43.   struct chrp_header hdr;
  44.   u32 adler;
  45.   u32 generation;
  46.   u32 reserved[2];
  47. };
  48. /*
  49.  * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
  50.  */
  51. static int nvram_naddrs;
  52. static volatile unsigned char *nvram_addr;
  53. static volatile unsigned char *nvram_data;
  54. static int nvram_mult, is_core_99;
  55. static int core99_bank = 0;
  56. static int nvram_partitions[3];
  57. /* FIXME: kmalloc fails to allocate the image now that I had to move it
  58.  *        before time_init(). For now, I allocate a static buffer here
  59.  *        but it's a waste of space on all but core99 machines
  60.  */
  61. #if 0
  62. static char* nvram_image;
  63. #else
  64. static char nvram_image[NVRAM_SIZE] __pmacdata;
  65. #endif
  66. extern int pmac_newworld;
  67. static u8 __openfirmware
  68. chrp_checksum(struct chrp_header* hdr)
  69. {
  70. u8 *ptr;
  71. u16 sum = hdr->signature;
  72. for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
  73. sum += *ptr;
  74. while (sum > 0xFF)
  75. sum = (sum & 0xFF) + (sum>>8);
  76. return sum;
  77. }
  78. static u32 __pmac
  79. core99_calc_adler(u8 *buffer)
  80. {
  81. int cnt;
  82. u32 low, high;
  83.     buffer += CORE99_ADLER_START;
  84. low = 1;
  85. high = 0;
  86. for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
  87. if ((cnt % 5000) == 0) {
  88. high  %= 65521UL;
  89. high %= 65521UL;
  90. }
  91. low += buffer[cnt];
  92. high += low;
  93. }
  94. low  %= 65521UL;
  95. high %= 65521UL;
  96.   
  97. return (high << 16) | low;
  98. }
  99. static u32 __pmac
  100. core99_check(u8* datas)
  101. {
  102. struct core99_header* hdr99 = (struct core99_header*)datas;
  103. if (hdr99->hdr.signature != CORE99_SIGNATURE) {
  104. #ifdef DEBUG
  105. printk("Invalid signaturen");
  106. #endif
  107. return 0;
  108. }
  109. if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
  110. #ifdef DEBUG
  111. printk("Invalid checksumn");
  112. #endif
  113. return 0;
  114. }
  115. if (hdr99->adler != core99_calc_adler(datas)) {
  116. #ifdef DEBUG
  117. printk("Invalid adlern");
  118. #endif
  119. return 0;
  120. }
  121. return hdr99->generation;
  122. }
  123. static int __pmac
  124. core99_erase_bank(int bank)
  125. {
  126. int stat, i;
  127. u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
  128. out_8(base, CORE99_FLASH_CMD_ERASE_SETUP);
  129. out_8(base, CORE99_FLASH_CMD_ERASE_CONFIRM);
  130. do { stat = in_8(base); }
  131. while(!(stat & CORE99_FLASH_STATUS_DONE));
  132. out_8(base, CORE99_FLASH_CMD_RESET);
  133. if (stat & CORE99_FLASH_STATUS_ERR) {
  134. printk("nvram: flash error 0x%02x on erase !n", stat);
  135. return -ENXIO;
  136. }
  137. for (i=0; i<NVRAM_SIZE; i++)
  138. if (base[i] != 0xff) {
  139. printk("nvram: flash erase failed !n");
  140. return -ENXIO;
  141. }
  142. return 0;
  143. }
  144. static int __pmac
  145. core99_write_bank(int bank, u8* datas)
  146. {
  147. int i, stat = 0;
  148. u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
  149. for (i=0; i<NVRAM_SIZE; i++) {
  150. out_8(base+i, CORE99_FLASH_CMD_WRITE_SETUP);
  151. out_8(base+i, datas[i]);
  152. do { stat = in_8(base); }
  153. while(!(stat & CORE99_FLASH_STATUS_DONE));
  154. if (stat & CORE99_FLASH_STATUS_ERR)
  155. break;
  156. }
  157. out_8(base, CORE99_FLASH_CMD_RESET);
  158. if (stat & CORE99_FLASH_STATUS_ERR) {
  159. printk("nvram: flash error 0x%02x on write !n", stat);
  160. return -ENXIO;
  161. }
  162. for (i=0; i<NVRAM_SIZE; i++)
  163. if (base[i] != datas[i]) {
  164. printk("nvram: flash write failed !n");
  165. return -ENXIO;
  166. }
  167. return 0;
  168. }
  169. static void __init
  170. lookup_partitions(void)
  171. {
  172. u8 buffer[17];
  173. int i, offset;
  174. struct chrp_header* hdr;
  175. if (pmac_newworld) {
  176. nvram_partitions[pmac_nvram_OF] = -1;
  177. nvram_partitions[pmac_nvram_XPRAM] = -1;
  178. nvram_partitions[pmac_nvram_NR] = -1;
  179. hdr = (struct chrp_header *)buffer;
  180. offset = 0;
  181. buffer[16] = 0;
  182. do {
  183. for (i=0;i<16;i++)
  184. buffer[i] = nvram_read_byte(offset+i);
  185. if (!strcmp(hdr->name, "common"))
  186. nvram_partitions[pmac_nvram_OF] = offset + 0x10;
  187. if (!strcmp(hdr->name, "APL,MacOS75")) {
  188. nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10;
  189. nvram_partitions[pmac_nvram_NR] = offset + 0x110;
  190. }
  191. offset += (hdr->len * 0x10);
  192. } while(offset < NVRAM_SIZE);
  193. } else {
  194. nvram_partitions[pmac_nvram_OF] = 0x1800;
  195. nvram_partitions[pmac_nvram_XPRAM] = 0x1300;
  196. nvram_partitions[pmac_nvram_NR] = 0x1400;
  197. }
  198. #ifdef DEBUG
  199. printk("nvram: OF partition at 0x%xn", nvram_partitions[pmac_nvram_OF]);
  200. printk("nvram: XP partition at 0x%xn", nvram_partitions[pmac_nvram_XPRAM]);
  201. printk("nvram: NR partition at 0x%xn", nvram_partitions[pmac_nvram_NR]);
  202. #endif
  203. }
  204. void __init
  205. pmac_nvram_init(void)
  206. {
  207. struct device_node *dp;
  208. nvram_naddrs = 0;
  209. dp = find_devices("nvram");
  210. if (dp == NULL) {
  211. printk(KERN_ERR "Can't find NVRAM devicen");
  212. return;
  213. }
  214. nvram_naddrs = dp->n_addrs;
  215. is_core_99 = device_is_compatible(dp, "nvram,flash");
  216. if (is_core_99) {
  217. int i;
  218. u32 gen_bank0, gen_bank1;
  219. if (nvram_naddrs < 1) {
  220. printk(KERN_ERR "nvram: no addressn");
  221. return;
  222. }
  223. #if 0
  224. nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL);
  225. if (!nvram_image) {
  226. printk(KERN_ERR "nvram: can't allocate imagen");
  227. return;
  228. }
  229. #endif
  230. nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
  231. #ifdef DEBUG
  232. printk("nvram: Checking bank 0...n");
  233. #endif
  234. gen_bank0 = core99_check((u8 *)nvram_data);
  235. gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
  236. core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
  237. #ifdef DEBUG
  238. printk("nvram: gen0=%d, gen1=%dn", gen_bank0, gen_bank1);
  239. printk("nvram: Active bank is: %dn", core99_bank);
  240. #endif
  241. for (i=0; i<NVRAM_SIZE; i++)
  242. nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
  243. } else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
  244. nvram_data = ioremap(dp->addrs[0].address + isa_mem_base,
  245.      dp->addrs[0].size);
  246. nvram_mult = 1;
  247. } else if (nvram_naddrs == 1) {
  248. nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
  249. nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
  250. } else if (nvram_naddrs == 2) {
  251. nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
  252. nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
  253. } else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
  254. nvram_naddrs = -1;
  255. } else {
  256. printk(KERN_ERR "Don't know how to access NVRAM with %d addressesn",
  257.        nvram_naddrs);
  258. }
  259. lookup_partitions();
  260. }
  261. void __pmac
  262. pmac_nvram_update(void)
  263. {
  264. struct core99_header* hdr99;
  265. if (!is_core_99 || !nvram_data || !nvram_image)
  266. return;
  267. if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
  268. NVRAM_SIZE))
  269. return;
  270. #ifdef DEBUG
  271. printk("Updating nvram...n");
  272. #endif
  273. hdr99 = (struct core99_header*)nvram_image;
  274. hdr99->generation++;
  275. hdr99->hdr.signature = CORE99_SIGNATURE;
  276. hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
  277. hdr99->adler = core99_calc_adler(nvram_image);
  278. core99_bank = core99_bank ? 0 : 1;
  279. if (core99_erase_bank(core99_bank)) {
  280. printk("nvram: Error erasing bank %dn", core99_bank);
  281. return;
  282. }
  283. if (core99_write_bank(core99_bank, nvram_image))
  284. printk("nvram: Error writing bank %dn", core99_bank);
  285. }
  286. unsigned char __openfirmware
  287. nvram_read_byte(int addr)
  288. {
  289. switch (nvram_naddrs) {
  290. #ifdef CONFIG_ADB_PMU
  291. case -1: {
  292. struct adb_request req;
  293. if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM,
  294. (addr >> 8) & 0xff, addr & 0xff))
  295. break;
  296. while (!req.complete)
  297. pmu_poll();
  298. return req.reply[0];
  299. }
  300. #endif
  301. case 1:
  302. if (is_core_99)
  303. return nvram_image[addr];
  304. return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
  305. case 2:
  306. *nvram_addr = addr >> 5;
  307. eieio();
  308. return nvram_data[(addr & 0x1f) << 4];
  309. }
  310. return 0;
  311. }
  312. void __openfirmware
  313. nvram_write_byte(unsigned char val, int addr)
  314. {
  315. switch (nvram_naddrs) {
  316. #ifdef CONFIG_ADB_PMU
  317. case -1: {
  318. struct adb_request req;
  319. if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM,
  320. (addr >> 8) & 0xff, addr & 0xff, val))
  321. break;
  322. while (!req.complete)
  323. pmu_poll();
  324. break;
  325. }
  326. #endif
  327. case 1:
  328. if (is_core_99) {
  329. nvram_image[addr] = val;
  330. break;
  331. }
  332. nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
  333. break;
  334. case 2:
  335. *nvram_addr = addr >> 5;
  336. eieio();
  337. nvram_data[(addr & 0x1f) << 4] = val;
  338. break;
  339. }
  340. eieio();
  341. }
  342. int __pmac
  343. pmac_get_partition(int partition)
  344. {
  345. return nvram_partitions[partition];
  346. }
  347. u8 __pmac
  348. pmac_xpram_read(int xpaddr)
  349. {
  350. int offset = nvram_partitions[pmac_nvram_XPRAM];
  351. if (offset < 0)
  352. return 0;
  353. return nvram_read_byte(xpaddr + offset);
  354. }
  355. void __pmac
  356. pmac_xpram_write(int xpaddr, u8 data)
  357. {
  358. int offset = nvram_partitions[pmac_nvram_XPRAM];
  359. if (offset < 0)
  360. return;
  361. nvram_write_byte(xpaddr + offset, data);
  362. }