2 * Support for Medifield PNW Camera Imaging ISP subsystem.
4 * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
6 * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * ISP MMU driver for classic two-level page tables
29 #include <linux/types.h>
30 #include <linux/mutex.h>
31 #include <linux/slab.h>
34 * do not change these values, the page size for ISP must be the
35 * same as kernel's page size.
37 #define ISP_PAGE_OFFSET 12
38 #define ISP_PAGE_SIZE (1U << ISP_PAGE_OFFSET)
39 #define ISP_PAGE_MASK (~(phys_addr_t)(ISP_PAGE_SIZE - 1))
41 #define ISP_L1PT_OFFSET 22
42 #define ISP_L1PT_MASK (~((1U << ISP_L1PT_OFFSET) - 1))
44 #define ISP_L2PT_OFFSET 12
45 #define ISP_L2PT_MASK (~(ISP_L1PT_MASK|(~(ISP_PAGE_MASK))))
47 #define ISP_L1PT_PTES 1024
48 #define ISP_L2PT_PTES 1024
50 #define ISP_PTR_TO_L1_IDX(x) ((((x) & ISP_L1PT_MASK)) \
53 #define ISP_PTR_TO_L2_IDX(x) ((((x) & ISP_L2PT_MASK)) \
56 #define ISP_PAGE_ALIGN(x) (((x) + (ISP_PAGE_SIZE-1)) \
59 #define ISP_PT_TO_VIRT(l1_idx, l2_idx, offset) do {\
60 ((l1_idx) << ISP_L1PT_OFFSET) | \
61 ((l2_idx) << ISP_L2PT_OFFSET) | \
65 #define pgnr_to_size(pgnr) ((pgnr) << ISP_PAGE_OFFSET)
66 #define size_to_pgnr_ceil(size) (((size) + (1 << ISP_PAGE_OFFSET) - 1)\
68 #define size_to_pgnr_bottom(size) ((size) >> ISP_PAGE_OFFSET)
72 struct isp_mmu_client {
79 * should be 1 bit valid data, meaning the value should
83 unsigned int pte_valid_mask;
84 unsigned int null_pte;
87 * set/get page directory base address (physical address).
91 int (*set_pd_base) (struct isp_mmu *mmu,
93 unsigned int (*get_pd_base) (struct isp_mmu *mmu, phys_addr_t pd_base);
95 * callback to flush tlb.
97 * tlb_flush_range will at least flush TLBs containing
98 * address mapping from addr to addr + size.
100 * tlb_flush_all will flush all TLBs.
102 * tlb_flush_all is must be provided. if tlb_flush_range is
103 * not valid, it will set to tlb_flush_all by default.
105 void (*tlb_flush_range) (struct isp_mmu *mmu,
106 unsigned int addr, unsigned int size);
107 void (*tlb_flush_all) (struct isp_mmu *mmu);
108 unsigned int (*phys_to_pte) (struct isp_mmu *mmu,
110 phys_addr_t (*pte_to_phys) (struct isp_mmu *mmu,
116 struct isp_mmu_client *driver;
118 int l2_pgt_refcount[ISP_L1PT_PTES];
119 phys_addr_t base_address;
121 struct mutex pt_mutex;
122 struct kmem_cache *tbl_cache;
125 /* flags for PDE and PTE */
126 #define ISP_PTE_VALID_MASK(mmu) \
127 ((mmu)->driver->pte_valid_mask)
129 #define ISP_PTE_VALID(mmu, pte) \
130 ((pte) & ISP_PTE_VALID_MASK(mmu))
132 #define NULL_PAGE ((phys_addr_t)(-1) & ISP_PAGE_MASK)
133 #define PAGE_VALID(page) ((page) != NULL_PAGE)
136 * init mmu with specific mmu driver.
138 int isp_mmu_init(struct isp_mmu *mmu, struct isp_mmu_client *driver);
140 * cleanup all mmu related things.
142 void isp_mmu_exit(struct isp_mmu *mmu);
145 * setup/remove address mapping for pgnr continous physical pages
148 * map/unmap is mutex lock protected, and caller does not have
149 * to do lock/unlock operation.
151 * map/unmap will not flush tlb, and caller needs to deal with
154 int isp_mmu_map(struct isp_mmu *mmu, unsigned int isp_virt,
155 phys_addr_t phys, unsigned int pgnr);
157 void isp_mmu_unmap(struct isp_mmu *mmu, unsigned int isp_virt,
160 static inline void isp_mmu_flush_tlb_all(struct isp_mmu *mmu)
162 if (mmu->driver && mmu->driver->tlb_flush_all)
163 mmu->driver->tlb_flush_all(mmu);
166 #define isp_mmu_flush_tlb isp_mmu_flush_tlb_all
168 static inline void isp_mmu_flush_tlb_range(struct isp_mmu *mmu,
169 unsigned int start, unsigned int size)
171 if (mmu->driver && mmu->driver->tlb_flush_range)
172 mmu->driver->tlb_flush_range(mmu, start, size);
175 #endif /* ISP_MMU_H_ */