Subversion Repositories HelenOS

Rev

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