Subversion Repositories HelenOS

Rev

Rev 4055 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2006 Jakub Jermar
  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 sparc64
  30.  * @{
  31.  */
  32. /**
  33.  * @file
  34.  * @brief   PCI driver.
  35.  */
  36.  
  37. #include <arch/drivers/pci.h>
  38. #include <genarch/ofw/ofw_tree.h>
  39. #include <arch/trap/interrupt.h>
  40. #include <mm/page.h>
  41. #include <mm/slab.h>
  42. #include <arch/types.h>
  43. #include <debug.h>
  44. #include <print.h>
  45. #include <string.h>
  46. #include <arch/asm.h>
  47. #include <sysinfo/sysinfo.h>
  48.  
  49. #define SABRE_INTERNAL_REG  0
  50. #define PSYCHO_INTERNAL_REG 2  
  51.  
  52. #define OBIO_IMR_BASE   0x200
  53. #define OBIO_IMR(ino)   (OBIO_IMR_BASE + ((ino) & INO_MASK))
  54.  
  55. #define OBIO_CIR_BASE   0x300
  56. #define OBIO_CIR(ino)   (OBIO_CIR_BASE + ((ino) & INO_MASK))
  57.  
  58. static void obio_enable_interrupt(pci_t *, int);
  59. static void obio_clear_interrupt(pci_t *, int);
  60.  
  61. static pci_t *pci_sabre_init(ofw_tree_node_t *);
  62. static pci_t *pci_psycho_init(ofw_tree_node_t *);
  63.  
  64. /** PCI operations for Sabre model. */
  65. static pci_operations_t pci_sabre_ops = {
  66.     .enable_interrupt = obio_enable_interrupt,
  67.     .clear_interrupt = obio_clear_interrupt
  68. };
  69. /** PCI operations for Psycho model. */
  70. static pci_operations_t pci_psycho_ops = {
  71.     .enable_interrupt = obio_enable_interrupt,
  72.     .clear_interrupt = obio_clear_interrupt
  73. };
  74.  
  75. /** Initialize PCI controller (model Sabre).
  76.  *
  77.  * @param node      OpenFirmware device tree node of the Sabre.
  78.  *
  79.  * @return      Address of the initialized PCI structure.
  80.  */
  81. pci_t *pci_sabre_init(ofw_tree_node_t *node)
  82. {
  83.     pci_t *pci;
  84.     ofw_tree_property_t *prop;
  85.  
  86.     /*
  87.      * Get registers.
  88.      */
  89.     prop = ofw_tree_getprop(node, "reg");
  90.     if (!prop || !prop->value)
  91.         return NULL;
  92.  
  93.     ofw_upa_reg_t *reg = prop->value;
  94.     count_t regs = prop->size / sizeof(ofw_upa_reg_t);
  95.  
  96.     if (regs < SABRE_INTERNAL_REG + 1)
  97.         return NULL;
  98.  
  99.     uintptr_t paddr;
  100.     if (!ofw_upa_apply_ranges(node->parent, &reg[SABRE_INTERNAL_REG],
  101.         &paddr))
  102.         return NULL;
  103.  
  104.     pci = (pci_t *) malloc(sizeof(pci_t), FRAME_ATOMIC);
  105.     if (!pci)
  106.         return NULL;
  107.  
  108.     pci->model = PCI_SABRE;
  109.     pci->op = &pci_sabre_ops;
  110.     pci->reg = (uint64_t *) hw_map(paddr, reg[SABRE_INTERNAL_REG].size);
  111.  
  112.     /*
  113.      * Set sysinfo data needed by the uspace OBIO driver.
  114.      */
  115.     sysinfo_set_item_val("obio.base.physical", NULL, paddr);
  116.     sysinfo_set_item_val("kbd.cir.obio", NULL, 1);
  117.  
  118.     return pci;
  119. }
  120.  
  121.  
  122. /** Initialize the Psycho PCI controller.
  123.  *
  124.  * @param node      OpenFirmware device tree node of the Psycho.
  125.  *
  126.  * @return      Address of the initialized PCI structure.
  127.  */
  128. pci_t *pci_psycho_init(ofw_tree_node_t *node)
  129. {
  130.     pci_t *pci;
  131.     ofw_tree_property_t *prop;
  132.  
  133.     /*
  134.      * Get registers.
  135.      */
  136.     prop = ofw_tree_getprop(node, "reg");
  137.     if (!prop || !prop->value)
  138.         return NULL;
  139.  
  140.     ofw_upa_reg_t *reg = prop->value;
  141.     count_t regs = prop->size / sizeof(ofw_upa_reg_t);
  142.  
  143.     if (regs < PSYCHO_INTERNAL_REG + 1)
  144.         return NULL;
  145.  
  146.     uintptr_t paddr;
  147.     if (!ofw_upa_apply_ranges(node->parent, &reg[PSYCHO_INTERNAL_REG],
  148.         &paddr))
  149.         return NULL;
  150.  
  151.     pci = (pci_t *) malloc(sizeof(pci_t), FRAME_ATOMIC);
  152.     if (!pci)
  153.         return NULL;
  154.  
  155.     pci->model = PCI_PSYCHO;
  156.     pci->op = &pci_psycho_ops;
  157.     pci->reg = (uint64_t *) hw_map(paddr, reg[PSYCHO_INTERNAL_REG].size);
  158.  
  159.     /*
  160.      * Set sysinfo data needed by the uspace OBIO driver.
  161.      */
  162.     sysinfo_set_item_val("obio.base.physical", NULL, paddr);
  163.     sysinfo_set_item_val("kbd.cir.obio", NULL, 1);
  164.  
  165.     return pci;
  166. }
  167.  
  168. void obio_enable_interrupt(pci_t *pci, int inr)
  169. {
  170.     pci->reg[OBIO_IMR(inr & INO_MASK)] |= IMAP_V_MASK;
  171. }
  172.  
  173. void obio_clear_interrupt(pci_t *pci, int inr)
  174. {
  175.     pci->reg[OBIO_CIR(inr & INO_MASK)] = 0; /* set IDLE */
  176. }
  177.  
  178. /** Initialize PCI controller. */
  179. pci_t *pci_init(ofw_tree_node_t *node)
  180. {
  181.     ofw_tree_property_t *prop;
  182.  
  183.     /*
  184.      * First, verify this is a PCI node.
  185.      */
  186.     ASSERT(str_cmp(ofw_tree_node_name(node), "pci") == 0);
  187.  
  188.     /*
  189.      * Determine PCI controller model.
  190.      */
  191.     prop = ofw_tree_getprop(node, "model");
  192.     if (!prop || !prop->value)
  193.         return NULL;
  194.    
  195.     if (str_cmp(prop->value, "SUNW,sabre") == 0) {
  196.         /*
  197.          * PCI controller Sabre.
  198.          * This model is found on UltraSPARC IIi based machines.
  199.          */
  200.         return pci_sabre_init(node);
  201.     } else if (str_cmp(prop->value, "SUNW,psycho") == 0) {
  202.         /*
  203.          * PCI controller Psycho.
  204.          * Used on UltraSPARC II based processors, for instance,
  205.          * on Ultra 60.
  206.          */
  207.         return pci_psycho_init(node);
  208.     } else {
  209.         /*
  210.          * Unsupported model.
  211.          */
  212.         printf("Unsupported PCI controller model (%s).\n", prop->value);
  213.     }
  214.  
  215.     return NULL;
  216. }
  217.  
  218. void pci_enable_interrupt(pci_t *pci, int inr)
  219. {
  220.     ASSERT(pci->op && pci->op->enable_interrupt);
  221.     pci->op->enable_interrupt(pci, inr);
  222. }
  223.  
  224. void pci_clear_interrupt(void *pcip, int inr)
  225. {
  226.     pci_t *pci = (pci_t *)pcip;
  227.  
  228.     ASSERT(pci->op && pci->op->clear_interrupt);
  229.     pci->op->clear_interrupt(pci, inr);
  230. }
  231.  
  232. /** @}
  233.  */
  234.