Subversion Repositories HelenOS

Rev

Rev 4676 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2009 Vineeth Pillai
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /** @addtogroup arm32integratorcp
  30.  * @{
  31.  */
  32. /** @file
  33.  *  @brief ICP drivers.
  34.  */
  35.  
  36. #include <interrupt.h>
  37. #include <ipc/irq.h>
  38. #include <console/chardev.h>
  39. #include <genarch/drivers/pl050/pl050.h>
  40. #include <genarch/kbrd/kbrd.h>
  41. #include <console/console.h>
  42. #include <sysinfo/sysinfo.h>
  43. #include <print.h>
  44. #include <ddi/device.h>
  45. #include <mm/page.h>
  46. #include <mm/frame.h>
  47. #include <arch/mm/frame.h>
  48. #include <arch/mach/integratorcp/integratorcp.h>
  49. #include <genarch/fb/fb.h>
  50. #include <genarch/fb/visuals.h>
  51. #include <ddi/ddi.h>
  52. #include <print.h>
  53.  
  54. #define SDRAM_SIZE  (sdram[((*(uint32_t *)(ICP_CMCR+ICP_SDRAMCR_OFFSET) & ICP_SDRAM_MASK) >> 2)])
  55. static parea_t fb_parea;
  56. static icp_hw_map_t icp_hw_map;
  57. static irq_t icp_timer_irq;
  58. struct arm_machine_ops machine_ops = {
  59.     MACHINE_GENFUNC,
  60.     MACHINE_GENFUNC,
  61.     icp_init,
  62.     icp_timer_irq_start,
  63.     icp_cpu_halt,
  64.     icp_get_memory_size,
  65.     icp_fb_init,
  66.     icp_irq_exception,
  67.     icp_get_fb_address,
  68.     icp_frame_init,
  69.     icp_output_init,
  70.     icp_input_init
  71. };
  72.  
  73. static bool hw_map_init_called = false;
  74. static bool vga_init = false;
  75. uint32_t sdram[8] = {
  76.     16777216,   /* 16mb */
  77.     33554432,   /* 32mb */
  78.     67108864,   /* 64mb */
  79.     134217728,  /* 128mb */
  80.     268435456,  /* 256mb */
  81.     0,      /* Reserverd */
  82.     0,      /* Reserverd */
  83.     0       /* Reserverd */
  84.     };
  85.  
  86. void icp_vga_init(void);
  87.  
  88. /** Initializes the vga
  89.  *
  90.  */
  91. void icp_vga_init(void)
  92. {
  93.     *(uint32_t*)((char *)(icp_hw_map.cmcr)+0x14) = 0xA05F0000;
  94.     *(uint32_t*)((char *)(icp_hw_map.cmcr)+0x1C) = 0x12C11000;
  95.     *(uint32_t*)icp_hw_map.vga = 0x3F1F3F9C;
  96.     *(uint32_t*)((char *)(icp_hw_map.vga) + 0x4) = 0x080B61DF;
  97.     *(uint32_t*)((char *)(icp_hw_map.vga) + 0x8) = 0x067F3800;
  98.     *(uint32_t*)((char *)(icp_hw_map.vga) + 0x10) = ICP_FB;
  99.     *(uint32_t *)((char *)(icp_hw_map.vga) + 0x1C) = 0x182B;
  100.     *(uint32_t*)((char *)(icp_hw_map.cmcr)+0xC) = 0x33805000;
  101.    
  102. }
  103.  
  104. /** Returns the mask of active interrupts. */
  105. static inline uint32_t icp_irqc_get_sources(void)
  106. {
  107.     return *((uint32_t *) icp_hw_map.irqc);
  108. }
  109.  
  110.  
  111. /** Masks interrupt.
  112.  *
  113.  * @param irq interrupt number
  114.  */
  115. static inline void icp_irqc_mask(uint32_t irq)
  116. {
  117.     *((uint32_t *) icp_hw_map.irqc_mask) = (1 << irq);
  118. }
  119.  
  120.  
  121. /** Unmasks interrupt.
  122.  *
  123.  * @param irq interrupt number
  124.  */
  125. static inline void icp_irqc_unmask(uint32_t irq)
  126. {
  127.     *((uint32_t *) icp_hw_map.irqc_unmask) |= (1 << irq);
  128. }
  129.  
  130. /** Initializes the icp frame buffer */
  131. void icp_fb_init(void)
  132. {
  133.     fb_properties_t prop = {
  134.         .addr = 0,
  135.         .offset = 0,
  136.         .x = 640,
  137.         .y = 480,
  138.         .scan = 2560,
  139.         .visual = VISUAL_BGR_0_8_8_8,
  140.     };
  141.     prop.addr = icp_get_fb_address();
  142.     fb_init(&prop);
  143.     fb_parea.pbase = ICP_FB;
  144.     fb_parea.frames = 300;
  145.     ddi_parea_register(&fb_parea);
  146. }
  147.  
  148. /** Initializes icp_hw_map. */
  149. void icp_init(void)
  150. {
  151.     icp_hw_map.uart = hw_map(ICP_UART, PAGE_SIZE);
  152.     icp_hw_map.kbd_ctrl = hw_map(ICP_KBD, PAGE_SIZE);
  153.     icp_hw_map.kbd_stat = icp_hw_map.kbd_ctrl + ICP_KBD_STAT;
  154.     icp_hw_map.kbd_data = icp_hw_map.kbd_ctrl + ICP_KBD_DATA;
  155.     icp_hw_map.kbd_intstat = icp_hw_map.kbd_ctrl + ICP_KBD_INTR_STAT;
  156.     icp_hw_map.rtc = hw_map(ICP_RTC, PAGE_SIZE);
  157.     icp_hw_map.rtc1_load = icp_hw_map.rtc + ICP_RTC1_LOAD_OFFSET;
  158.     icp_hw_map.rtc1_read = icp_hw_map.rtc + ICP_RTC1_READ_OFFSET;
  159.     icp_hw_map.rtc1_ctl = icp_hw_map.rtc + ICP_RTC1_CTL_OFFSET;
  160.     icp_hw_map.rtc1_intrclr = icp_hw_map.rtc + ICP_RTC1_INTRCLR_OFFSET;
  161.     icp_hw_map.rtc1_bgload = icp_hw_map.rtc + ICP_RTC1_BGLOAD_OFFSET;
  162.     icp_hw_map.rtc1_intrstat = icp_hw_map.rtc + ICP_RTC1_INTRSTAT_OFFSET;
  163.  
  164.     icp_hw_map.irqc = hw_map(ICP_IRQC, PAGE_SIZE);
  165.     icp_hw_map.irqc_mask = icp_hw_map.irqc + ICP_IRQC_MASK_OFFSET;
  166.     icp_hw_map.irqc_unmask = icp_hw_map.irqc + ICP_IRQC_UNMASK_OFFSET;
  167.     icp_hw_map.cmcr = hw_map(ICP_CMCR, PAGE_SIZE);
  168.     icp_hw_map.sdramcr = icp_hw_map.cmcr + ICP_SDRAMCR_OFFSET;
  169.     icp_hw_map.vga = hw_map(ICP_VGA, PAGE_SIZE);
  170.  
  171.     hw_map_init_called = true;
  172. }
  173.  
  174.  
  175. /** Acquire console back for kernel. */
  176. void icp_grab_console(void)
  177. {
  178. }
  179.  
  180. /** Return console to userspace. */
  181. void icp_release_console(void)
  182. {
  183. }
  184.  
  185. /** Starts icp Real Time Clock device, which asserts regular interrupts.
  186.  *
  187.  * @param frequency Interrupts frequency (0 disables RTC).
  188.  */
  189. static void icp_timer_start(uint32_t frequency)
  190. {
  191.     icp_irqc_mask(ICP_TIMER_IRQ);
  192.     *((uint32_t*) icp_hw_map.rtc1_load) = frequency;
  193.     *((uint32_t*) icp_hw_map.rtc1_bgload) = frequency;
  194.     *((uint32_t*) icp_hw_map.rtc1_ctl) = ICP_RTC_CTL_VALUE;
  195.     icp_irqc_unmask(ICP_TIMER_IRQ);
  196. }
  197.  
  198. static irq_ownership_t icp_timer_claim(irq_t *irq)
  199. {
  200.     if (icp_hw_map.rtc1_intrstat) {
  201.         *((uint32_t*) icp_hw_map.rtc1_intrclr) = 1;
  202.         return IRQ_ACCEPT;
  203.     } else
  204.         return IRQ_DECLINE;
  205. }
  206.  
  207. /** Timer interrupt handler.
  208.  *
  209.  * @param irq Interrupt information.
  210.  * @param arg Not used.
  211.  */
  212. static void icp_timer_irq_handler(irq_t *irq)
  213. {
  214.     /*
  215.     * We are holding a lock which prevents preemption.
  216.     * Release the lock, call clock() and reacquire the lock again.
  217.     */
  218.  
  219.     spinlock_unlock(&irq->lock);
  220.     clock();
  221.     spinlock_lock(&irq->lock);
  222.  
  223. }
  224.  
  225. /** Initializes and registers timer interrupt handler. */
  226. static void icp_timer_irq_init(void)
  227. {
  228.     irq_initialize(&icp_timer_irq);
  229.     icp_timer_irq.devno = device_assign_devno();
  230.     icp_timer_irq.inr = ICP_TIMER_IRQ;
  231.     icp_timer_irq.claim = icp_timer_claim;
  232.     icp_timer_irq.handler = icp_timer_irq_handler;
  233.  
  234.     irq_register(&icp_timer_irq);
  235. }
  236.  
  237.  
  238. /** Starts timer.
  239.  *
  240.  * Initiates regular timer interrupts after initializing
  241.  * corresponding interrupt handler.
  242.  */
  243. void icp_timer_irq_start(void)
  244. {
  245.     icp_timer_irq_init();
  246.     icp_timer_start(ICP_TIMER_FREQ);
  247. }
  248.  
  249. /** Returns the size of emulated memory.
  250.  *
  251.  * @return Size in bytes.
  252.  */
  253. size_t icp_get_memory_size(void)
  254. {
  255.     if (hw_map_init_called) {
  256.         return (sdram[((*(uint32_t *)icp_hw_map.sdramcr & ICP_SDRAM_MASK) >> 2)]);
  257.     } else {
  258.         return SDRAM_SIZE;
  259.     }
  260.    
  261. }
  262.  
  263. /** Stops icp. */
  264. void icp_cpu_halt(void)
  265. {
  266.     while (1);
  267. }
  268.  
  269. /** interrupt exception handler.
  270.  *
  271.  * Determines sources of the interrupt from interrupt controller and
  272.  * calls high-level handlers for them.
  273.  *
  274.  * @param exc_no Interrupt exception number.
  275.  * @param istate Saved processor state.
  276.  */
  277. void icp_irq_exception(int exc_no, istate_t *istate)
  278. {
  279.     uint32_t sources = icp_irqc_get_sources();
  280.     int i;
  281.    
  282.     for (i = 0; i < ICP_IRQC_MAX_IRQ; i++) {
  283.         if (sources & (1 << i)) {
  284.             irq_t *irq = irq_dispatch_and_lock(i);
  285.             if (irq) {
  286.                 /* The IRQ handler was found. */
  287.                 irq->handler(irq);
  288.                 spinlock_unlock(&irq->lock);
  289.             } else {
  290.                 /* Spurious interrupt.*/
  291.                 printf("cpu%d: spurious interrupt (inum=%d)\n",
  292.                     CPU->id, i);
  293.             }
  294.         }
  295.     }
  296. }
  297.  
  298. /** Returns address of framebuffer device.
  299.  *
  300.  *  @return Address of framebuffer device.
  301.  */
  302. uintptr_t icp_get_fb_address(void)
  303. {
  304.     if (!vga_init) {
  305.         icp_vga_init();
  306.         vga_init = true;
  307.     }
  308.     return (uintptr_t) ICP_FB;
  309. }
  310.  
  311. /*
  312.  * Integrator specific frame initialization
  313.  */
  314. void
  315. icp_frame_init(void)
  316. {
  317.     frame_mark_unavailable(ICP_FB_FRAME, ICP_FB_NUM_FRAME);
  318.     frame_mark_unavailable(0, 256);
  319. }
  320.  
  321. void icp_output_init(void)
  322. {
  323. }
  324.  
  325. void icp_input_init(void)
  326. {
  327.  
  328.     pl050_t *pl050 = malloc(sizeof(pl050_t), FRAME_ATOMIC);
  329.     pl050->status = (ioport8_t *)icp_hw_map.kbd_stat;
  330.     pl050->data = (ioport8_t *)icp_hw_map.kbd_data;
  331.     pl050->ctrl = (ioport8_t *)icp_hw_map.kbd_ctrl;
  332.        
  333.     pl050_instance_t *pl050_instance = pl050_init(pl050, ICP_KBD_IRQ);
  334.     if (pl050_instance) {
  335.         kbrd_instance_t *kbrd_instance = kbrd_init();
  336.         if (kbrd_instance) {
  337.             icp_irqc_mask(ICP_KBD_IRQ);
  338.             indev_t *sink = stdin_wire();
  339.             indev_t *kbrd = kbrd_wire(kbrd_instance, sink);
  340.             pl050_wire(pl050_instance, kbrd);
  341.             icp_irqc_unmask(ICP_KBD_IRQ);
  342.         }
  343.     }
  344.  
  345.     /*
  346.      * This is the necessary evil until the userspace driver is entirely
  347.      * self-sufficient.
  348.      */
  349.     sysinfo_set_item_val("kbd", NULL, true);
  350.     sysinfo_set_item_val("kbd.inr", NULL, ICP_KBD_IRQ);
  351.     sysinfo_set_item_val("kbd.address.status", NULL,
  352.         (uintptr_t) icp_hw_map.kbd_stat);
  353.     sysinfo_set_item_val("kbd.address.data", NULL,
  354.         (uintptr_t) icp_hw_map.kbd_data);
  355.  
  356. }
  357.  
  358.  
  359. /** @}
  360.  */
  361.