central.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:13k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* $Id: central.c,v 1.14.2.2 2002/03/01 01:26:50 davem Exp $
  2.  * central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
  3.  *
  4.  * Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com)
  5.  */
  6. #include <linux/kernel.h>
  7. #include <linux/types.h>
  8. #include <linux/string.h>
  9. #include <linux/timer.h>
  10. #include <linux/sched.h>
  11. #include <linux/delay.h>
  12. #include <linux/init.h>
  13. #include <linux/bootmem.h>
  14. #include <asm/page.h>
  15. #include <asm/fhc.h>
  16. #include <asm/starfire.h>
  17. struct linux_central *central_bus = NULL;
  18. struct linux_fhc *fhc_list = NULL;
  19. #define IS_CENTRAL_FHC(__fhc) ((__fhc) == central_bus->child)
  20. static inline unsigned long long_align(unsigned long addr)
  21. {
  22. return ((addr + (sizeof(unsigned long) - 1)) &
  23. ~(sizeof(unsigned long) - 1));
  24. }
  25. static void central_ranges_init(int cnode, struct linux_central *central)
  26. {
  27. int success;
  28. central->num_central_ranges = 0;
  29. success = prom_getproperty(central->prom_node, "ranges",
  30.    (char *) central->central_ranges,
  31.    sizeof (central->central_ranges));
  32. if (success != -1)
  33. central->num_central_ranges = (success/sizeof(struct linux_prom_ranges));
  34. }
  35. static void fhc_ranges_init(int fnode, struct linux_fhc *fhc)
  36. {
  37. int success;
  38. fhc->num_fhc_ranges = 0;
  39. success = prom_getproperty(fhc->prom_node, "ranges",
  40.    (char *) fhc->fhc_ranges,
  41.    sizeof (fhc->fhc_ranges));
  42. if (success != -1)
  43. fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges));
  44. }
  45. /* Range application routines are exported to various drivers,
  46.  * so do not __init this.
  47.  */
  48. static void adjust_regs(struct linux_prom_registers *regp, int nregs,
  49. struct linux_prom_ranges *rangep, int nranges)
  50. {
  51. int regc, rngc;
  52. for (regc = 0; regc < nregs; regc++) {
  53. for (rngc = 0; rngc < nranges; rngc++)
  54. if (regp[regc].which_io == rangep[rngc].ot_child_space)
  55. break; /* Fount it */
  56. if (rngc == nranges) /* oops */
  57. prom_printf("adjust_regs: Could not find range with matching bus type...n");
  58. regp[regc].which_io = rangep[rngc].ot_parent_space;
  59. regp[regc].phys_addr -= rangep[rngc].ot_child_base;
  60. regp[regc].phys_addr += rangep[rngc].ot_parent_base;
  61. }
  62. }
  63. /* Apply probed fhc ranges to registers passed, if no ranges return. */
  64. void apply_fhc_ranges(struct linux_fhc *fhc,
  65.       struct linux_prom_registers *regs,
  66.       int nregs)
  67. {
  68. if(fhc->num_fhc_ranges)
  69. adjust_regs(regs, nregs, fhc->fhc_ranges,
  70.     fhc->num_fhc_ranges);
  71. }
  72. /* Apply probed central ranges to registers passed, if no ranges return. */
  73. void apply_central_ranges(struct linux_central *central,
  74.   struct linux_prom_registers *regs, int nregs)
  75. {
  76. if(central->num_central_ranges)
  77. adjust_regs(regs, nregs, central->central_ranges,
  78.     central->num_central_ranges);
  79. }
  80. void * __init central_alloc_bootmem(unsigned long size)
  81. {
  82. void *ret;
  83. ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
  84. if (ret != NULL)
  85. memset(ret, 0, size);
  86. return ret;
  87. }
  88. static void probe_other_fhcs(void)
  89. {
  90. struct linux_prom64_registers fpregs[6];
  91. char namebuf[128];
  92. int node;
  93. node = prom_getchild(prom_root_node);
  94. node = prom_searchsiblings(node, "fhc");
  95. if (node == 0) {
  96. prom_printf("FHC: Cannot find any toplevel firehose controllers.n");
  97. prom_halt();
  98. }
  99. while(node) {
  100. struct linux_fhc *fhc;
  101. int board;
  102. u32 tmp;
  103. fhc = (struct linux_fhc *)
  104. central_alloc_bootmem(sizeof(struct linux_fhc));
  105. if (fhc == NULL) {
  106. prom_printf("probe_other_fhcs: Cannot alloc fhc.n");
  107. prom_halt();
  108. }
  109. /* Link it into the FHC chain. */
  110. fhc->next = fhc_list;
  111. fhc_list = fhc;
  112. /* Toplevel FHCs have no parent. */
  113. fhc->parent = NULL;
  114. fhc->prom_node = node;
  115. prom_getstring(node, "name", namebuf, sizeof(namebuf));
  116. strcpy(fhc->prom_name, namebuf);
  117. fhc_ranges_init(node, fhc);
  118. /* Non-central FHC's have 64-bit OBP format registers. */
  119. if(prom_getproperty(node, "reg",
  120.     (char *)&fpregs[0], sizeof(fpregs)) == -1) {
  121. prom_printf("FHC: Fatal error, cannot get fhc regs.n");
  122. prom_halt();
  123. }
  124. /* Only central FHC needs special ranges applied. */
  125. fhc->fhc_regs.pregs = fpregs[0].phys_addr;
  126. fhc->fhc_regs.ireg = fpregs[1].phys_addr;
  127. fhc->fhc_regs.ffregs = fpregs[2].phys_addr;
  128. fhc->fhc_regs.sregs = fpregs[3].phys_addr;
  129. fhc->fhc_regs.uregs = fpregs[4].phys_addr;
  130. fhc->fhc_regs.tregs = fpregs[5].phys_addr;
  131. board = prom_getintdefault(node, "board#", -1);
  132. fhc->board = board;
  133. tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_JCTRL);
  134. if((tmp & FHC_JTAG_CTRL_MENAB) != 0)
  135. fhc->jtag_master = 1;
  136. else
  137. fhc->jtag_master = 0;
  138. tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID);
  139. printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] %sn",
  140.        board,
  141.        (tmp & FHC_ID_VERS) >> 28,
  142.        (tmp & FHC_ID_PARTID) >> 12,
  143.        (tmp & FHC_ID_MANUF) >> 1,
  144.        (fhc->jtag_master ? "(JTAG Master)" : ""));
  145. /* This bit must be set in all non-central FHC's in
  146.  * the system.  When it is clear, this identifies
  147.  * the central board.
  148.  */
  149. tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
  150. tmp |= FHC_CONTROL_IXIST;
  151. upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
  152. /* Look for the next FHC. */
  153. node = prom_getsibling(node);
  154. if(node == 0)
  155. break;
  156. node = prom_searchsiblings(node, "fhc");
  157. if(node == 0)
  158. break;
  159. }
  160. }
  161. static void probe_clock_board(struct linux_central *central,
  162.       struct linux_fhc *fhc,
  163.       int cnode, int fnode)
  164. {
  165. struct linux_prom_registers cregs[3];
  166. int clknode, nslots, tmp, nregs;
  167. clknode = prom_searchsiblings(prom_getchild(fnode), "clock-board");
  168. if(clknode == 0 || clknode == -1) {
  169. prom_printf("Critical error, central lacks clock-board.n");
  170. prom_halt();
  171. }
  172. nregs = prom_getproperty(clknode, "reg", (char *)&cregs[0], sizeof(cregs));
  173. if (nregs == -1) {
  174. prom_printf("CENTRAL: Fatal error, cannot map clock-board regs.n");
  175. prom_halt();
  176. }
  177. nregs /= sizeof(struct linux_prom_registers);
  178. apply_fhc_ranges(fhc, &cregs[0], nregs);
  179. apply_central_ranges(central, &cregs[0], nregs);
  180. central->cfreg = ((((unsigned long)cregs[0].which_io) << 32UL) |
  181.   ((unsigned long)cregs[0].phys_addr));
  182. central->clkregs = ((((unsigned long)cregs[1].which_io) << 32UL) |
  183.     ((unsigned long)cregs[1].phys_addr));
  184. if(nregs == 2)
  185. central->clkver = 0UL;
  186. else
  187. central->clkver = ((((unsigned long)cregs[2].which_io) << 32UL) |
  188.    ((unsigned long)cregs[2].phys_addr));
  189. tmp = upa_readb(central->clkregs + CLOCK_STAT1);
  190. tmp &= 0xc0;
  191. switch(tmp) {
  192. case 0x40:
  193. nslots = 16;
  194. break;
  195. case 0xc0:
  196. nslots = 8;
  197. break;
  198. case 0x80:
  199. if(central->clkver != 0UL &&
  200.    upa_readb(central->clkver) != 0) {
  201. if((upa_readb(central->clkver) & 0x80) != 0)
  202. nslots = 4;
  203. else
  204. nslots = 5;
  205. break;
  206. }
  207. default:
  208. nslots = 4;
  209. break;
  210. };
  211. central->slots = nslots;
  212. printk("CENTRAL: Detected %d slot Enterprise system. cfreg[%02x] cver[%02x]n",
  213.        central->slots, upa_readb(central->cfreg),
  214.        (central->clkver ? upa_readb(central->clkver) : 0x00));
  215. }
  216. static void init_all_fhc_hw(void)
  217. {
  218. struct linux_fhc *fhc;
  219. for(fhc = fhc_list; fhc != NULL; fhc = fhc->next) {
  220. u32 tmp;
  221. /* Clear all of the interrupt mapping registers
  222.  * just in case OBP left them in a foul state.
  223.  */
  224. #define ZAP(ICLR, IMAP) 
  225. do { u32 imap_tmp; 
  226. upa_writel(0, (ICLR)); 
  227. upa_readl(ICLR); 
  228. imap_tmp = upa_readl(IMAP); 
  229. imap_tmp &= ~(0x80000000); 
  230. upa_writel(imap_tmp, (IMAP)); 
  231. upa_readl(IMAP); 
  232. } while (0)
  233. ZAP(fhc->fhc_regs.ffregs + FHC_FFREGS_ICLR,
  234.     fhc->fhc_regs.ffregs + FHC_FFREGS_IMAP);
  235. ZAP(fhc->fhc_regs.sregs + FHC_SREGS_ICLR,
  236.     fhc->fhc_regs.sregs + FHC_SREGS_IMAP);
  237. ZAP(fhc->fhc_regs.uregs + FHC_UREGS_ICLR,
  238.     fhc->fhc_regs.uregs + FHC_UREGS_IMAP);
  239. ZAP(fhc->fhc_regs.tregs + FHC_TREGS_ICLR,
  240.     fhc->fhc_regs.tregs + FHC_TREGS_IMAP);
  241. #undef ZAP
  242. /* Setup FHC control register. */
  243. tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
  244. /* All non-central boards have this bit set. */
  245. if(! IS_CENTRAL_FHC(fhc))
  246. tmp |= FHC_CONTROL_IXIST;
  247. /* For all FHCs, clear the firmware synchronization
  248.  * line and both low power mode enables.
  249.  */
  250. tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE);
  251. upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
  252. upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
  253. }
  254. }
  255. void central_probe(void)
  256. {
  257. struct linux_prom_registers fpregs[6];
  258. struct linux_fhc *fhc;
  259. char namebuf[128];
  260. int cnode, fnode, err;
  261. cnode = prom_finddevice("/central");
  262. if(cnode == 0 || cnode == -1) {
  263. if (this_is_starfire)
  264. starfire_cpu_setup();
  265. return;
  266. }
  267. /* Ok we got one, grab some memory for software state. */
  268. central_bus = (struct linux_central *)
  269. central_alloc_bootmem(sizeof(struct linux_central));
  270. if (central_bus == NULL) {
  271. prom_printf("central_probe: Cannot alloc central_bus.n");
  272. prom_halt();
  273. }
  274. fhc = (struct linux_fhc *)
  275. central_alloc_bootmem(sizeof(struct linux_fhc));
  276. if (fhc == NULL) {
  277. prom_printf("central_probe: Cannot alloc central fhc.n");
  278. prom_halt();
  279. }
  280. /* First init central. */
  281. central_bus->child = fhc;
  282. central_bus->prom_node = cnode;
  283. prom_getstring(cnode, "name", namebuf, sizeof(namebuf));
  284. strcpy(central_bus->prom_name, namebuf);
  285. central_ranges_init(cnode, central_bus);
  286. /* And then central's FHC. */
  287. fhc->next = fhc_list;
  288. fhc_list = fhc;
  289. fhc->parent = central_bus;
  290. fnode = prom_searchsiblings(prom_getchild(cnode), "fhc");
  291. if(fnode == 0 || fnode == -1) {
  292. prom_printf("Critical error, central board lacks fhc.n");
  293. prom_halt();
  294. }
  295. fhc->prom_node = fnode;
  296. prom_getstring(fnode, "name", namebuf, sizeof(namebuf));
  297. strcpy(fhc->prom_name, namebuf);
  298. fhc_ranges_init(fnode, fhc);
  299. /* Now, map in FHC register set. */
  300. if (prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs)) == -1) {
  301. prom_printf("CENTRAL: Fatal error, cannot get fhc regs.n");
  302. prom_halt();
  303. }
  304. apply_central_ranges(central_bus, &fpregs[0], 6);
  305. fhc->fhc_regs.pregs = ((((unsigned long)fpregs[0].which_io)<<32UL) |
  306.        ((unsigned long)fpregs[0].phys_addr));
  307. fhc->fhc_regs.ireg = ((((unsigned long)fpregs[1].which_io)<<32UL) |
  308.       ((unsigned long)fpregs[1].phys_addr));
  309. fhc->fhc_regs.ffregs = ((((unsigned long)fpregs[2].which_io)<<32UL) |
  310. ((unsigned long)fpregs[2].phys_addr));
  311. fhc->fhc_regs.sregs = ((((unsigned long)fpregs[3].which_io)<<32UL) |
  312.        ((unsigned long)fpregs[3].phys_addr));
  313. fhc->fhc_regs.uregs = ((((unsigned long)fpregs[4].which_io)<<32UL) |
  314.        ((unsigned long)fpregs[4].phys_addr));
  315. fhc->fhc_regs.tregs = ((((unsigned long)fpregs[5].which_io)<<32UL) |
  316.        ((unsigned long)fpregs[5].phys_addr));
  317. /* Obtain board number from board status register, Central's
  318.  * FHC lacks "board#" property.
  319.  */
  320. err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_BSR);
  321. fhc->board = (((err >> 16) & 0x01) |
  322.       ((err >> 12) & 0x0e));
  323. fhc->jtag_master = 0;
  324. /* Attach the clock board registers for CENTRAL. */
  325. probe_clock_board(central_bus, fhc, cnode, fnode);
  326. err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID);
  327. printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)n",
  328.        fhc->board,
  329.        ((err & FHC_ID_VERS) >> 28),
  330.        ((err & FHC_ID_PARTID) >> 12),
  331.        ((err & FHC_ID_MANUF) >> 1));
  332. probe_other_fhcs();
  333. init_all_fhc_hw();
  334. }
  335. static __inline__ void fhc_ledblink(struct linux_fhc *fhc, int on)
  336. {
  337. u32 tmp;
  338. tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
  339. /* NOTE: reverse logic on this bit */
  340. if (on)
  341. tmp &= ~(FHC_CONTROL_RLED);
  342. else
  343. tmp |= FHC_CONTROL_RLED;
  344. tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE);
  345. upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
  346. upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
  347. }
  348. static __inline__ void central_ledblink(struct linux_central *central, int on)
  349. {
  350. u8 tmp;
  351. tmp = upa_readb(central->clkregs + CLOCK_CTRL);
  352. /* NOTE: reverse logic on this bit */
  353. if(on)
  354. tmp &= ~(CLOCK_CTRL_RLED);
  355. else
  356. tmp |= CLOCK_CTRL_RLED;
  357. upa_writeb(tmp, central->clkregs + CLOCK_CTRL);
  358. upa_readb(central->clkregs + CLOCK_CTRL);
  359. }
  360. static struct timer_list sftimer;
  361. static int led_state;
  362. static void sunfire_timer(unsigned long __ignored)
  363. {
  364. struct linux_fhc *fhc;
  365. central_ledblink(central_bus, led_state);
  366. for(fhc = fhc_list; fhc != NULL; fhc = fhc->next)
  367. if(! IS_CENTRAL_FHC(fhc))
  368. fhc_ledblink(fhc, led_state);
  369. led_state = ! led_state;
  370. sftimer.expires = jiffies + (HZ >> 1);
  371. add_timer(&sftimer);
  372. }
  373. /* After PCI/SBUS busses have been probed, this is called to perform
  374.  * final initialization of all FireHose Controllers in the system.
  375.  */
  376. void firetruck_init(void)
  377. {
  378. struct linux_central *central = central_bus;
  379. u8 ctrl;
  380. /* No central bus, nothing to do. */
  381. if (central == NULL)
  382. return;
  383. /* OBP leaves it on, turn it off so clock board timer LED
  384.  * is in sync with FHC ones.
  385.  */
  386. ctrl = upa_readb(central->clkregs + CLOCK_CTRL);
  387. ctrl &= ~(CLOCK_CTRL_RLED);
  388. upa_writeb(ctrl, central->clkregs + CLOCK_CTRL);
  389. led_state = 0;
  390. init_timer(&sftimer);
  391. sftimer.data = 0;
  392. sftimer.function = &sunfire_timer;
  393. sftimer.expires = jiffies + (HZ >> 1);
  394. add_timer(&sftimer);
  395. }