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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * setup.c: SGI specific setup, including init of the feature struct.
  3.  *
  4.  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  5.  * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org)
  6.  */
  7. #include <linux/config.h>
  8. #include <linux/init.h>
  9. #include <linux/kbd_ll.h>
  10. #include <linux/kernel.h>
  11. #include <linux/kdev_t.h>
  12. #include <linux/types.h>
  13. #include <linux/console.h>
  14. #include <linux/sched.h>
  15. #include <linux/mc146818rtc.h>
  16. #include <linux/pc_keyb.h>
  17. #include <asm/addrspace.h>
  18. #include <asm/bcache.h>
  19. #include <asm/keyboard.h>
  20. #include <asm/irq.h>
  21. #include <asm/reboot.h>
  22. #include <asm/sgialib.h>
  23. #include <asm/sgi/sgimc.h>
  24. #include <asm/sgi/sgihpc.h>
  25. #include <asm/sgi/sgint23.h>
  26. #include <asm/time.h>
  27. #include <asm/gdb-stub.h>
  28. #ifdef CONFIG_REMOTE_DEBUG
  29. extern void rs_kgdb_hook(int);
  30. extern void breakpoint(void);
  31. static int remote_debug = 0;
  32. #endif
  33. #if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_ARC_CONSOLE)
  34. extern void console_setup(char *);
  35. #endif
  36. extern unsigned long r4k_interval; /* Cycle counter ticks per 1/HZ seconds */
  37. extern struct rtc_ops indy_rtc_ops;
  38. void indy_reboot_setup(void);
  39. void sgi_volume_set(unsigned char);
  40. #define sgi_kh ((struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64))
  41. #define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
  42. static void sgi_request_region(void)
  43. {
  44. /* No I/O ports are being used on the Indy.  */
  45. }
  46. static int sgi_request_irq(void (*handler)(int, void *, struct pt_regs *))
  47. {
  48. /* Dirty hack, this get's called as a callback from the keyboard
  49.    driver.  We piggyback the initialization of the front panel
  50.    button handling on it even though they're technically not
  51.    related with the keyboard driver in any way.  Doing it from
  52.    indy_setup wouldn't work since kmalloc isn't initialized yet.  */
  53. indy_reboot_setup();
  54. return request_irq(SGI_KEYBOARD_IRQ, handler, 0, "keyboard", NULL);
  55. }
  56. static int sgi_aux_request_irq(void (*handler)(int, void *, struct pt_regs *))
  57. {
  58. /* Nothing to do, interrupt is shared with the keyboard hw  */
  59. return 0;
  60. }
  61. static void sgi_aux_free_irq(void)
  62. {
  63. /* Nothing to do, interrupt is shared with the keyboard hw  */
  64. }
  65. static unsigned char sgi_read_input(void)
  66. {
  67. return sgi_kh->data;
  68. }
  69. static void sgi_write_output(unsigned char val)
  70. {
  71. int status;
  72. do {
  73. status = sgi_kh->command;
  74. } while (status & KBD_STAT_IBF);
  75. sgi_kh->data = val;
  76. }
  77. static void sgi_write_command(unsigned char val)
  78. {
  79. int status;
  80. do {
  81. status = sgi_kh->command;
  82. } while (status & KBD_STAT_IBF);
  83. sgi_kh->command = val;
  84. }
  85. static unsigned char sgi_read_status(void)
  86. {
  87. return sgi_kh->command;
  88. }
  89. struct kbd_ops sgi_kbd_ops = {
  90. sgi_request_region,
  91. sgi_request_irq,
  92. sgi_aux_request_irq,
  93. sgi_aux_free_irq,
  94. sgi_read_input,
  95. sgi_write_output,
  96. sgi_write_command,
  97. sgi_read_status
  98. };
  99. static unsigned long dosample(volatile unsigned char *tcwp,
  100.                               volatile unsigned char *tc2p)
  101. {
  102.         unsigned long ct0, ct1;
  103.         unsigned char msb, lsb;
  104.         /* Start the counter. */
  105.         *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MRGEN);
  106.         *tc2p = (SGINT_TCSAMP_COUNTER & 0xff);
  107.         *tc2p = (SGINT_TCSAMP_COUNTER >> 8);
  108.         /* Get initial counter invariant */
  109.         ct0 = read_32bit_cp0_register(CP0_COUNT);
  110.         /* Latch and spin until top byte of counter2 is zero */
  111.         do {
  112.                 *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT);
  113.                 lsb = *tc2p;
  114.                 msb = *tc2p;
  115.                 ct1 = read_32bit_cp0_register(CP0_COUNT);
  116.         } while(msb);
  117. /* Stop the counter. */
  118. *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MSWST);
  119. /*
  120.  * Return the difference, this is how far the r4k counter increments
  121.  * for every 1/HZ seconds. We round off the nearest 1 MHz of master
  122.  * clock (= 1000000 / 100 / 2 = 5000 count).
  123.  */
  124. return ((ct1 - ct0) / 5000) * 5000;
  125. }
  126. #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
  127. void sgi_time_init (struct irqaction *irq) {
  128. /* Here we need to calibrate the cycle counter to at least be close.
  129.  * We don't need to actually register the irq handler because that's
  130.  * all done in indyIRQ.S.
  131.  */
  132.         struct sgi_ioc_timers *p;
  133.         volatile unsigned char *tcwp, *tc2p;
  134. unsigned long r4k_ticks[3];
  135. unsigned long r4k_next;
  136.         /* Figure out the r4k offset, the algorithm is very simple
  137.          * and works in _all_ cases as long as the 8254 counter
  138.          * register itself works ok (as an interrupt driving timer
  139.          * it does not because of bug, this is why we are using
  140.          * the onchip r4k counter/compare register to serve this
  141.          * purpose, but for r4k_offset calculation it will work
  142.          * ok for us).  There are other very complicated ways
  143.          * of performing this calculation but this one works just
  144.          * fine so I am not going to futz around. ;-)
  145.          */
  146.         p = ioc_timers;
  147.         tcwp = &p->tcword;
  148.         tc2p = &p->tcnt2;
  149.         printk("Calibrating system timer... ");
  150.         dosample(tcwp, tc2p);                   /* Prime cache. */
  151.         dosample(tcwp, tc2p);                   /* Prime cache. */
  152. /* Zero is NOT an option. */
  153. do {
  154. r4k_ticks[0] = dosample (tcwp, tc2p);
  155. } while (!r4k_ticks[0]);
  156. do {
  157. r4k_ticks[1] = dosample (tcwp, tc2p);
  158. } while (!r4k_ticks[1]);
  159. if (r4k_ticks[0] != r4k_ticks[1]) {
  160. printk ("warning: timer counts differ, retrying...");
  161. r4k_ticks[2] = dosample (tcwp, tc2p);
  162. if (r4k_ticks[2] == r4k_ticks[0] 
  163.     || r4k_ticks[2] == r4k_ticks[1])
  164. r4k_interval = r4k_ticks[2];
  165. else {
  166. printk ("disagreement, using average...");
  167. r4k_interval = (r4k_ticks[0] + r4k_ticks[1] 
  168. + r4k_ticks[2]) / 3;
  169. }
  170. } else
  171. r4k_interval = r4k_ticks[0];
  172.         printk("%d [%d.%02d MHz CPU]n", (int) r4k_interval, 
  173. (int) (r4k_interval / 5000), (int) (r4k_interval % 5000) / 50);
  174. /* Set ourselves up for future interrupts */
  175.         r4k_next = (read_32bit_cp0_register(CP0_COUNT) + r4k_interval);
  176.         write_32bit_cp0_register(CP0_COMPARE, r4k_next);
  177.         change_cp0_status(ST0_IM, ALLINTS);
  178. sti ();
  179. }
  180. void __init sgi_setup(void)
  181. {
  182. #ifdef CONFIG_SERIAL_CONSOLE
  183. char *ctype;
  184. #endif
  185. #ifdef CONFIG_REMOTE_DEBUG
  186. char *kgdb_ttyd;
  187. #endif
  188. board_time_init = sgi_time_init;
  189. /* Init the INDY HPC I/O controller.  Need to call this before
  190.  * fucking with the memory controller because it needs to know the
  191.  * boardID and whether this is a Guiness or a FullHouse machine.
  192.  */
  193. sgihpc_init();
  194. /* Init INDY memory controller. */
  195. sgimc_init();
  196. /* Now enable boardcaches, if any. */
  197. indy_sc_init();
  198. #ifdef CONFIG_SERIAL_CONSOLE
  199. /* ARCS console environment variable is set to "g?" for
  200.  * graphics console, it is set to "d" for the first serial
  201.  * line and "d2" for the second serial line.
  202.  */
  203. ctype = ArcGetEnvironmentVariable("console");
  204. if(*ctype == 'd') {
  205. if(*(ctype+1)=='2')
  206. console_setup ("ttyS1");
  207. else
  208. console_setup ("ttyS0");
  209. }
  210. #endif
  211. #ifdef CONFIG_REMOTE_DEBUG
  212. kgdb_ttyd = prom_getcmdline();
  213. if ((kgdb_ttyd = strstr(kgdb_ttyd, "kgdb=ttyd")) != NULL) {
  214. int line;
  215. kgdb_ttyd += strlen("kgdb=ttyd");
  216. if (*kgdb_ttyd != '1' && *kgdb_ttyd != '2')
  217. printk("KGDB: Uknown serial line /dev/ttyd%c, "
  218.        "falling back to /dev/ttyd1n", *kgdb_ttyd);
  219. line = *kgdb_ttyd == '2' ? 0 : 1;
  220. printk("KGDB: Using serial line /dev/ttyd%d for sessionn",
  221.        line ? 1 : 2);
  222. rs_kgdb_hook(line);
  223. printk("KGDB: Using serial line /dev/ttyd%d for session, "
  224.     "please connect your debuggern", line ? 1 : 2);
  225. remote_debug = 1;
  226. /* Breakpoints and stuff are in sgi_irq_setup() */
  227. }
  228. #endif
  229. #ifdef CONFIG_ARC_CONSOLE
  230. console_setup("ttyS0");
  231. #endif
  232.  
  233. sgi_volume_set(simple_strtoul(ArcGetEnvironmentVariable("volume"), NULL, 10));
  234. #ifdef CONFIG_VT
  235. #ifdef CONFIG_SGI_NEWPORT_CONSOLE
  236. conswitchp = &newport_con;
  237. screen_info = (struct screen_info) {
  238. 0, 0, /* orig-x, orig-y */
  239. 0, /* unused */
  240. 0, /* orig_video_page */
  241. 0, /* orig_video_mode */
  242. 160, /* orig_video_cols */
  243. 0, 0, 0, /* unused, ega_bx, unused */
  244. 64, /* orig_video_lines */
  245. 0, /* orig_video_isVGA */
  246. 16 /* orig_video_points */
  247. };
  248. #else
  249. conswitchp = &dummy_con;
  250. #endif
  251. #endif
  252. rtc_ops = &indy_rtc_ops;
  253. kbd_ops = &sgi_kbd_ops;
  254. #ifdef CONFIG_PSMOUSE
  255. aux_device_present = 0xaa;
  256. #endif
  257. #ifdef CONFIG_VIDEO_VINO
  258. init_vino();
  259. #endif
  260. }