2 ** Proll (PROM replacement)
3 ** iommu.c: Functions for DVMA management.
4 ** Copyright 1999 Pete Zaitcev
5 ** This code is licensed under GNU General Public License.
8 #include "libopenbios/bindings.h"
9 #include "libopenbios/ofmem.h"
10 #include "drivers/drivers.h"
12 #include "arch/sparc32/ofmem_sparc32.h"
14 #ifdef CONFIG_DEBUG_IOMMU
15 #define DPRINTF(fmt, args...) \
16 do { printk(fmt , ##args); } while (0)
18 #define DPRINTF(fmt, args...)
25 struct iommu_regs *regs;
26 unsigned int *page_table;
27 unsigned long plow; /* Base bus address */
30 static struct iommu ciommu;
33 iommu_invalidate(struct iommu_regs *iregs)
39 * XXX This is a problematic interface. We alloc _memory_ which is uncached.
40 * So if we ever reuse allocations somebody is going to get uncached pages.
41 * Returned address is always aligned by page.
42 * BTW, we were not going to give away anonymous storage, were we not?
45 dvma_alloc(int size, unsigned int *pphys)
50 unsigned int mva, mpa;
53 struct iommu *t = &ciommu;
56 npages = (size + (PAGE_SIZE-1)) / PAGE_SIZE;
57 ret = ofmem_posix_memalign(&va, npages * PAGE_SIZE, PAGE_SIZE);
61 ba = (unsigned int)mem_alloc(&cdvmem, npages * PAGE_SIZE, PAGE_SIZE);
65 pa = (unsigned int)va2pa((unsigned long)va);
68 * Change page attributes in MMU to uncached.
70 mva = (unsigned int) va;
71 mpa = (unsigned int) pa;
72 ofmem_arch_map_pages(mpa, mva, npages * PAGE_SIZE, ofmem_arch_io_translation_mode(mpa));
75 * Map into IOMMU page table.
77 mpa = (unsigned int) pa;
78 iopte = &t->page_table[(ba - t->plow) / PAGE_SIZE];
79 for (i = 0; i < npages; i++) {
80 *iopte++ = MKIOPTE(mpa);
91 * This looks like initialization of CPU MMU but
92 * the routine is higher in food chain.
94 static struct iommu_regs *
95 iommu_init(struct iommu *t, uint64_t base)
99 #ifdef CONFIG_DEBUG_IOMMU
100 unsigned int impl, vers;
103 struct iommu_regs *regs;
105 unsigned long vasize;
107 regs = (struct iommu_regs *)ofmem_map_io(base, IOMMU_REGS);
109 DPRINTF("Cannot map IOMMU\n");
113 #ifdef CONFIG_DEBUG_IOMMU
114 impl = (regs->control & IOMMU_CTRL_IMPL) >> 28;
115 vers = (regs->control & IOMMU_CTRL_VERS) >> 24;
119 tmp &= ~(IOMMU_CTRL_RNGE);
121 tmp |= (IOMMU_RNGE_32MB | IOMMU_CTRL_ENAB);
122 t->plow = 0xfe000000; /* End - 32 MB */
123 /* Size of VA region that we manage */
124 vasize = 0x2000000; /* 32 MB */
127 iommu_invalidate(regs);
129 /* Allocate IOMMU page table */
130 /* Tremendous alignment causes great waste... */
131 ptsize = (vasize / PAGE_SIZE) * sizeof(int);
132 ret = ofmem_posix_memalign((void *)&ptab, ptsize, ptsize);
134 DPRINTF("Cannot allocate IOMMU table [0x%x]\n", ptsize);
137 t->page_table = ptab;
139 /* flush_cache_all(); */
140 /** flush_tlb_all(); **/
141 tmp = (unsigned int)va2pa((unsigned long)ptab);
142 regs->base = tmp >> 4;
143 iommu_invalidate(regs);
145 DPRINTF("IOMMU: impl %d vers %d page table at 0x%p (pa 0x%x) of size %d bytes\n",
146 impl, vers, t->page_table, tmp, ptsize);
148 mem_init(&cdvmem, (char*)t->plow, (char *)0xfffff000);
152 /* ( addr.lo addr.hi size -- virt ) */
155 ob_iommu_map_in(void)
162 phys = (phys << 32) + POP();
164 virt = ofmem_map_io(phys, size);
172 ob_iommu_map_out(void)
177 ofmem_release_io(virt, size);
181 ob_init_iommu(uint64_t base)
183 struct iommu_regs *regs;
185 regs = iommu_init(&ciommu, base);
188 fword("find-device");
189 PUSH((unsigned long)regs);
196 PUSH(base & 0xffffffff);
205 bind_func("map-in", ob_iommu_map_in);
206 bind_func("map-out", ob_iommu_map_out);