Subversion Repositories HelenOS

Rev

Rev 2089 | 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 <func.h>
  46. #include <arch/asm.h>
  47.  
  48. #define PCI_SABRE_REGS_REG  0
  49.  
  50. #define PCI_SABRE_IMAP_BASE 0x200
  51. #define PCI_SABRE_ICLR_BASE 0x300
  52.  
  53. #define PCI_PSYCHO_REGS_REG 2  
  54.  
  55. #define PCI_PSYCHO_IMAP_BASE    0x200
  56. #define PCI_PSYCHO_ICLR_BASE    0x300  
  57.  
  58. static pci_t *pci_sabre_init(ofw_tree_node_t *node);
  59. static void pci_sabre_enable_interrupt(pci_t *pci, int inr);
  60. static void pci_sabre_clear_interrupt(pci_t *pci, int inr);
  61.  
  62. static pci_t *pci_psycho_init(ofw_tree_node_t *node);
  63. static void pci_psycho_enable_interrupt(pci_t *pci, int inr);
  64. static void pci_psycho_clear_interrupt(pci_t *pci, int inr);
  65.  
  66. /** PCI operations for Sabre model. */
  67. static pci_operations_t pci_sabre_ops = {
  68.     .enable_interrupt = pci_sabre_enable_interrupt,
  69.     .clear_interrupt = pci_sabre_clear_interrupt
  70. };
  71. /** PCI operations for Psycho model. */
  72. static pci_operations_t pci_psycho_ops = {
  73.     .enable_interrupt = pci_psycho_enable_interrupt,
  74.     .clear_interrupt = pci_psycho_clear_interrupt
  75. };
  76.  
  77. /** Initialize PCI controller (model Sabre).
  78.  *
  79.  * @param node OpenFirmware device tree node of the Sabre.
  80.  *
  81.  * @return Address of the initialized PCI structure.
  82.  */
  83. pci_t *pci_sabre_init(ofw_tree_node_t *node)
  84. {
  85.     pci_t *pci;
  86.     ofw_tree_property_t *prop;
  87.  
  88.     /*
  89.      * Get registers.
  90.      */
  91.     prop = ofw_tree_getprop(node, "reg");
  92.     if (!prop || !prop->value)
  93.         return NULL;
  94.  
  95.     ofw_upa_reg_t *reg = prop->value;
  96.     count_t regs = prop->size / sizeof(ofw_upa_reg_t);
  97.  
  98.     if (regs < PCI_SABRE_REGS_REG + 1)
  99.         return NULL;
  100.  
  101.     uintptr_t paddr;
  102.     if (!ofw_upa_apply_ranges(node->parent, &reg[PCI_SABRE_REGS_REG], &paddr))
  103.         return NULL;
  104.  
  105.     pci = (pci_t *) malloc(sizeof(pci_t), FRAME_ATOMIC);
  106.     if (!pci)
  107.         return NULL;
  108.  
  109.     pci->model = PCI_SABRE;
  110.     pci->op = &pci_sabre_ops;
  111.     pci->reg = (uint64_t *) hw_map(paddr, reg[PCI_SABRE_REGS_REG].size);
  112.  
  113.     return pci;
  114. }
  115.  
  116.  
  117. /** Initialize the Psycho PCI controller.
  118.  *
  119.  * @param node OpenFirmware device tree node of the Psycho.
  120.  *
  121.  * @return Address of the initialized PCI structure.
  122.  */
  123. pci_t *pci_psycho_init(ofw_tree_node_t *node)
  124. {
  125.     pci_t *pci;
  126.     ofw_tree_property_t *prop;
  127.  
  128.     /*
  129.      * Get registers.
  130.      */
  131.     prop = ofw_tree_getprop(node, "reg");
  132.     if (!prop || !prop->value)
  133.         return NULL;
  134.  
  135.     ofw_upa_reg_t *reg = prop->value;
  136.     count_t regs = prop->size / sizeof(ofw_upa_reg_t);
  137.  
  138.     if (regs < PCI_PSYCHO_REGS_REG + 1)
  139.         return NULL;
  140.  
  141.     uintptr_t paddr;
  142.     if (!ofw_upa_apply_ranges(node->parent, &reg[PCI_PSYCHO_REGS_REG], &paddr))
  143.         return NULL;
  144.  
  145.     pci = (pci_t *) malloc(sizeof(pci_t), FRAME_ATOMIC);
  146.     if (!pci)
  147.         return NULL;
  148.  
  149.     pci->model = PCI_PSYCHO;
  150.     pci->op = &pci_psycho_ops;
  151.     pci->reg = (uint64_t *) hw_map(paddr, reg[PCI_PSYCHO_REGS_REG].size);
  152.  
  153.     return pci;
  154. }
  155.  
  156. void pci_sabre_enable_interrupt(pci_t *pci, int inr)
  157. {
  158.     pci->reg[PCI_SABRE_IMAP_BASE + (inr & INO_MASK)] |= IMAP_V_MASK;
  159. }
  160.  
  161. void pci_sabre_clear_interrupt(pci_t *pci, int inr)
  162. {
  163.     pci->reg[PCI_SABRE_ICLR_BASE + (inr & INO_MASK)] = 0;
  164. }
  165.  
  166. void pci_psycho_enable_interrupt(pci_t *pci, int inr)
  167. {
  168.     pci->reg[PCI_PSYCHO_IMAP_BASE + (inr & INO_MASK)] |= IMAP_V_MASK;
  169. }
  170.  
  171. void pci_psycho_clear_interrupt(pci_t *pci, int inr)
  172. {
  173.     pci->reg[PCI_PSYCHO_ICLR_BASE + (inr & INO_MASK)] = 0;
  174. }
  175.  
  176. /** Initialize PCI controller. */
  177. pci_t *pci_init(ofw_tree_node_t *node)
  178. {
  179.     ofw_tree_property_t *prop;
  180.  
  181.     /*
  182.      * First, verify this is a PCI node.
  183.      */
  184.     ASSERT(strcmp(ofw_tree_node_name(node), "pci") == 0);
  185.  
  186.     /*
  187.      * Determine PCI controller model.
  188.      */
  189.     prop = ofw_tree_getprop(node, "model");
  190.     if (!prop || !prop->value)
  191.         return NULL;
  192.    
  193.     if (strcmp(prop->value, "SUNW,sabre") == 0) {
  194.         /*
  195.          * PCI controller Sabre.
  196.          * This model is found on UltraSPARC IIi based machines.
  197.          */
  198.         return pci_sabre_init(node);
  199.     } else if (strcmp(prop->value, "SUNW,psycho") == 0) {
  200.         /*
  201.          * PCI controller Psycho.
  202.          * Used on UltraSPARC II based processors, for instance,
  203.          * on Ultra 60.
  204.          */
  205.         return pci_psycho_init(node);
  206.     } else {
  207.         /*
  208.          * Unsupported model.
  209.          */
  210.         printf("Unsupported PCI controller model (%s).\n", prop->value);
  211.     }
  212.  
  213.     return NULL;
  214. }
  215.  
  216. void pci_enable_interrupt(pci_t *pci, int inr)
  217. {
  218.     ASSERT(pci->model);
  219.     ASSERT(pci->op && pci->op->enable_interrupt);
  220.     pci->op->enable_interrupt(pci, inr);
  221. }
  222.  
  223. void pci_clear_interrupt(pci_t *pci, int inr)
  224. {
  225.     ASSERT(pci->model);
  226.     ASSERT(pci->op && pci->op->clear_interrupt);
  227.     pci->op->clear_interrupt(pci, inr);
  228. }
  229.  
  230. /** @}
  231.  */
  232.