xref: /openbmc/linux/arch/sh/mm/ioremap_fixed.c (revision acf2c9685fb8295cb62a623d7358a1cfde8b07ea)
14d35b93aSMatt Fleming /*
24d35b93aSMatt Fleming  * Re-map IO memory to kernel address space so that we can access it.
34d35b93aSMatt Fleming  *
44d35b93aSMatt Fleming  * These functions should only be used when it is necessary to map a
54d35b93aSMatt Fleming  * physical address space into the kernel address space before ioremap()
64d35b93aSMatt Fleming  * can be used, e.g. early in boot before paging_init().
74d35b93aSMatt Fleming  *
84d35b93aSMatt Fleming  * Copyright (C) 2009  Matt Fleming
94d35b93aSMatt Fleming  */
104d35b93aSMatt Fleming 
114d35b93aSMatt Fleming #include <linux/vmalloc.h>
124d35b93aSMatt Fleming #include <linux/ioport.h>
134d35b93aSMatt Fleming #include <linux/module.h>
144d35b93aSMatt Fleming #include <linux/mm.h>
154d35b93aSMatt Fleming #include <linux/io.h>
164d35b93aSMatt Fleming #include <linux/bootmem.h>
174d35b93aSMatt Fleming #include <linux/proc_fs.h>
184d35b93aSMatt Fleming #include <linux/slab.h>
194d35b93aSMatt Fleming #include <asm/fixmap.h>
204d35b93aSMatt Fleming #include <asm/page.h>
214d35b93aSMatt Fleming #include <asm/pgalloc.h>
224d35b93aSMatt Fleming #include <asm/addrspace.h>
234d35b93aSMatt Fleming #include <asm/cacheflush.h>
244d35b93aSMatt Fleming #include <asm/tlbflush.h>
254d35b93aSMatt Fleming #include <asm/mmu.h>
264d35b93aSMatt Fleming #include <asm/mmu_context.h>
274d35b93aSMatt Fleming 
284d35b93aSMatt Fleming struct ioremap_map {
294d35b93aSMatt Fleming 	void __iomem *addr;
304d35b93aSMatt Fleming 	unsigned long size;
314d35b93aSMatt Fleming 	unsigned long fixmap_addr;
324d35b93aSMatt Fleming };
334d35b93aSMatt Fleming 
344d35b93aSMatt Fleming static struct ioremap_map ioremap_maps[FIX_N_IOREMAPS];
354d35b93aSMatt Fleming 
364d35b93aSMatt Fleming void __init ioremap_fixed_init(void)
374d35b93aSMatt Fleming {
384d35b93aSMatt Fleming 	struct ioremap_map *map;
394d35b93aSMatt Fleming 	int i;
404d35b93aSMatt Fleming 
414d35b93aSMatt Fleming 	for (i = 0; i < FIX_N_IOREMAPS; i++) {
424d35b93aSMatt Fleming 		map = &ioremap_maps[i];
434d35b93aSMatt Fleming 		map->fixmap_addr = __fix_to_virt(FIX_IOREMAP_BEGIN + i);
444d35b93aSMatt Fleming 	}
454d35b93aSMatt Fleming }
464d35b93aSMatt Fleming 
474d35b93aSMatt Fleming void __init __iomem *
48*acf2c968SPaul Mundt ioremap_fixed(resource_size_t phys_addr, unsigned long offset,
49*acf2c968SPaul Mundt 	      unsigned long size, pgprot_t prot)
504d35b93aSMatt Fleming {
514d35b93aSMatt Fleming 	enum fixed_addresses idx0, idx;
524d35b93aSMatt Fleming 	struct ioremap_map *map;
534d35b93aSMatt Fleming 	unsigned int nrpages;
544d35b93aSMatt Fleming 	int i, slot;
554d35b93aSMatt Fleming 
564d35b93aSMatt Fleming 	slot = -1;
574d35b93aSMatt Fleming 	for (i = 0; i < FIX_N_IOREMAPS; i++) {
584d35b93aSMatt Fleming 		map = &ioremap_maps[i];
594d35b93aSMatt Fleming 		if (!map->addr) {
604d35b93aSMatt Fleming 			map->size = size;
614d35b93aSMatt Fleming 			slot = i;
624d35b93aSMatt Fleming 			break;
634d35b93aSMatt Fleming 		}
644d35b93aSMatt Fleming 	}
654d35b93aSMatt Fleming 
664d35b93aSMatt Fleming 	if (slot < 0)
674d35b93aSMatt Fleming 		return NULL;
684d35b93aSMatt Fleming 
694d35b93aSMatt Fleming 	/*
704d35b93aSMatt Fleming 	 * Mappings have to fit in the FIX_IOREMAP area.
714d35b93aSMatt Fleming 	 */
724d35b93aSMatt Fleming 	nrpages = size >> PAGE_SHIFT;
734d35b93aSMatt Fleming 	if (nrpages > FIX_N_IOREMAPS)
744d35b93aSMatt Fleming 		return NULL;
754d35b93aSMatt Fleming 
764d35b93aSMatt Fleming 	/*
774d35b93aSMatt Fleming 	 * Ok, go for it..
784d35b93aSMatt Fleming 	 */
794d35b93aSMatt Fleming 	idx0 = FIX_IOREMAP_BEGIN + slot;
804d35b93aSMatt Fleming 	idx = idx0;
814d35b93aSMatt Fleming 	while (nrpages > 0) {
824d35b93aSMatt Fleming 		pgprot_val(prot) |= _PAGE_WIRED;
834d35b93aSMatt Fleming 		__set_fixmap(idx, phys_addr, prot);
844d35b93aSMatt Fleming 		phys_addr += PAGE_SIZE;
854d35b93aSMatt Fleming 		idx++;
864d35b93aSMatt Fleming 		--nrpages;
874d35b93aSMatt Fleming 	}
884d35b93aSMatt Fleming 
894d35b93aSMatt Fleming 	map->addr = (void __iomem *)(offset + map->fixmap_addr);
904d35b93aSMatt Fleming 	return map->addr;
914d35b93aSMatt Fleming }
924d35b93aSMatt Fleming 
934f744affSPaul Mundt int iounmap_fixed(void __iomem *addr)
944d35b93aSMatt Fleming {
954d35b93aSMatt Fleming 	enum fixed_addresses idx;
964d35b93aSMatt Fleming 	unsigned long virt_addr;
974d35b93aSMatt Fleming 	struct ioremap_map *map;
984d35b93aSMatt Fleming 	unsigned long offset;
994d35b93aSMatt Fleming 	unsigned int nrpages;
1004d35b93aSMatt Fleming 	int i, slot;
1014d35b93aSMatt Fleming 
1024d35b93aSMatt Fleming 	slot = -1;
1034d35b93aSMatt Fleming 	for (i = 0; i < FIX_N_IOREMAPS; i++) {
1044d35b93aSMatt Fleming 		map = &ioremap_maps[i];
1054d35b93aSMatt Fleming 		if (map->addr == addr) {
1064d35b93aSMatt Fleming 			slot = i;
1074d35b93aSMatt Fleming 			break;
1084d35b93aSMatt Fleming 		}
1094d35b93aSMatt Fleming 	}
1104d35b93aSMatt Fleming 
1114f744affSPaul Mundt 	/*
1124f744affSPaul Mundt 	 * If we don't match, it's not for us.
1134f744affSPaul Mundt 	 */
1144d35b93aSMatt Fleming 	if (slot < 0)
1154f744affSPaul Mundt 		return -EINVAL;
1164d35b93aSMatt Fleming 
1174d35b93aSMatt Fleming 	virt_addr = (unsigned long)addr;
1184d35b93aSMatt Fleming 
1194d35b93aSMatt Fleming 	offset = virt_addr & ~PAGE_MASK;
1204d35b93aSMatt Fleming 	nrpages = PAGE_ALIGN(offset + map->size - 1) >> PAGE_SHIFT;
1214d35b93aSMatt Fleming 
1224d35b93aSMatt Fleming 	idx = FIX_IOREMAP_BEGIN + slot + nrpages;
1234d35b93aSMatt Fleming 	while (nrpages > 0) {
124*acf2c968SPaul Mundt 		__clear_fixmap(idx, __pgprot(_PAGE_WIRED));
1254d35b93aSMatt Fleming 		--idx;
1264d35b93aSMatt Fleming 		--nrpages;
1274d35b93aSMatt Fleming 	}
1284d35b93aSMatt Fleming 
1294d35b93aSMatt Fleming 	map->size = 0;
1304d35b93aSMatt Fleming 	map->addr = NULL;
1314f744affSPaul Mundt 
1324f744affSPaul Mundt 	return 0;
1334d35b93aSMatt Fleming }
134