bonito.c 4.7 KB
Newer Older
phcoder's avatar
phcoder committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
/* bonito.c - PCI bonito interface.  */
/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2009  Free Software Foundation, Inc.
 *
 *  GRUB is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  GRUB is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <grub/pci.h>
#include <grub/misc.h>

static grub_uint32_t base_win[GRUB_MACHINE_PCI_NUM_WIN];
static const grub_size_t sizes_win[GRUB_MACHINE_PCI_NUM_WIN] = 
  {GRUB_MACHINE_PCI_WIN1_SIZE, GRUB_MACHINE_PCI_WIN_SIZE, 
   GRUB_MACHINE_PCI_WIN_SIZE};
/* Usage counters.  */
static int usage_win[GRUB_MACHINE_PCI_NUM_WIN];
static grub_addr_t addr_win[GRUB_MACHINE_PCI_NUM_WIN] = 
  {GRUB_MACHINE_PCI_WIN1_ADDR, GRUB_MACHINE_PCI_WIN2_ADDR,
   GRUB_MACHINE_PCI_WIN3_ADDR};

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
grub_bonito_type_t grub_bonito_type;

static volatile void *
config_addr (grub_pci_address_t addr)
{
  if (grub_bonito_type == GRUB_BONITO_2F)
    {
      GRUB_MACHINE_PCI_CONF_CTRL_REG_2F = 1 << ((addr >> 11) & 0xf);
      return (volatile void *) (GRUB_MACHINE_PCI_CONFSPACE_2F
				| (addr & 0x07ff));
    }
  else
    {

      if (addr >> 16)
	return (volatile void *) (GRUB_MACHINE_PCI_CONFSPACE_3A_EXT | addr);
      else
	return (volatile void *) (GRUB_MACHINE_PCI_CONFSPACE_3A | addr);
    }
}

grub_uint32_t
grub_pci_read (grub_pci_address_t addr)
{
  return *(volatile grub_uint32_t *) config_addr (addr);
}

grub_uint16_t
grub_pci_read_word (grub_pci_address_t addr)
{
  return *(volatile grub_uint16_t *) config_addr (addr);
}

grub_uint8_t
grub_pci_read_byte (grub_pci_address_t addr)
{
  return *(volatile grub_uint8_t *) config_addr (addr);
}

void
grub_pci_write (grub_pci_address_t addr, grub_uint32_t data)
{
  *(volatile grub_uint32_t *) config_addr (addr) = data;
}

void
grub_pci_write_word (grub_pci_address_t addr, grub_uint16_t data)
{
  *(volatile grub_uint16_t *) config_addr (addr) = data;
}

void
grub_pci_write_byte (grub_pci_address_t addr, grub_uint8_t data)
{
  *(volatile grub_uint8_t *) config_addr (addr) = data;
}


phcoder's avatar
phcoder committed
91
static inline void
92
write_bases_2f (void)
phcoder's avatar
phcoder committed
93 94 95 96 97 98
{
  int i;
  grub_uint32_t reg = 0;
  for (i = 0; i < GRUB_MACHINE_PCI_NUM_WIN; i++) 
    reg |= (((base_win[i] >> GRUB_MACHINE_PCI_WIN_SHIFT) 
	     & GRUB_MACHINE_PCI_WIN_MASK) 
99
	    << (i * GRUB_MACHINE_PCI_WIN_MASK_SIZE));
100
  GRUB_MACHINE_PCI_IO_CTRL_REG_2F = reg;
phcoder's avatar
phcoder committed
101 102
}

103
volatile void *
phcoder's avatar
phcoder committed
104 105 106
grub_pci_device_map_range (grub_pci_device_t dev __attribute__ ((unused)),
			   grub_addr_t base, grub_size_t size)
{
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
  if (grub_bonito_type == GRUB_BONITO_2F)
    {
      int i;
      grub_addr_t newbase;

      /* First try already used registers. */
      for (i = 0; i < GRUB_MACHINE_PCI_NUM_WIN; i++)
	if (usage_win[i] && base_win[i] <= base 
	    && base_win[i] + sizes_win[i] > base + size)
	  {
	    usage_win[i]++;
	    return (void *) 
	      (addr_win[i] | (base & GRUB_MACHINE_PCI_WIN_OFFSET_MASK));
	  }
      /* Map new register.  */
      newbase = base & ~GRUB_MACHINE_PCI_WIN_OFFSET_MASK;
      for (i = 0; i < GRUB_MACHINE_PCI_NUM_WIN; i++)
	if (!usage_win[i] && newbase <= base 
	    && newbase + sizes_win[i] > base + size)
	  {
	    usage_win[i]++;
	    base_win[i] = newbase;
	    write_bases_2f ();
	    return (void *) 
	      (addr_win[i] | (base & GRUB_MACHINE_PCI_WIN_OFFSET_MASK));
	  }
      grub_fatal ("Out of PCI windows.");
    }
  else
    {
      int region = 0;
      if (base >= 0x10000000
	  && base + size <= 0x18000000)
	region = 1;
      if (base >= 0x1c000000
	  && base + size <= 0x1f000000)
	region = 2;
      if (region == 0)
	grub_fatal ("Attempt to map out of regions");
      return (void *) (0xa0000000 | base);
    }
phcoder's avatar
phcoder committed
148 149
}

150 151 152 153 154 155 156 157
void *
grub_pci_device_map_range_cached (grub_pci_device_t dev,
				  grub_addr_t base, grub_size_t size)
{
  return (void *) (((grub_addr_t) grub_pci_device_map_range (dev, base, size))
		   & ~0x20000000);
}

phcoder's avatar
phcoder committed
158 159
void
grub_pci_device_unmap_range (grub_pci_device_t dev __attribute__ ((unused)),
160
			     volatile void *mem,
phcoder's avatar
phcoder committed
161 162
			     grub_size_t size __attribute__ ((unused)))
{
163 164 165 166 167 168 169 170 171 172 173 174 175
  if (grub_bonito_type == GRUB_BONITO_2F)
    {
      int i;
      for (i = 0; i < GRUB_MACHINE_PCI_NUM_WIN; i++)
	if (usage_win[i] && addr_win[i] 
	    == (((grub_addr_t) mem | 0x20000000)
		& ~GRUB_MACHINE_PCI_WIN_OFFSET_MASK))
	  {
	    usage_win[i]--;
	    return;
	  }
      grub_fatal ("Tried to unmap not mapped region");
    }
phcoder's avatar
phcoder committed
176
}