Linux-libre 4.14.12-gnu
[librecmc/linux-libre.git] / drivers / staging / media / atomisp / pci / atomisp2 / include / mmu / isp_mmu.h
1 /*
2  * Support for Medifield PNW Camera Imaging ISP subsystem.
3  *
4  * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
5  *
6  * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
7  *
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.
11  *
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.
16  *
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
20  * 02110-1301, USA.
21  *
22  */
23 /*
24  * ISP MMU driver for classic two-level page tables
25  */
26 #ifndef __ISP_MMU_H__
27 #define __ISP_MMU_H__
28
29 #include <linux/types.h>
30 #include <linux/mutex.h>
31 #include <linux/slab.h>
32
33 /*
34  * do not change these values, the page size for ISP must be the
35  * same as kernel's page size.
36  */
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))
40
41 #define ISP_L1PT_OFFSET         22
42 #define ISP_L1PT_MASK           (~((1U << ISP_L1PT_OFFSET) - 1))
43
44 #define ISP_L2PT_OFFSET         12
45 #define ISP_L2PT_MASK           (~(ISP_L1PT_MASK|(~(ISP_PAGE_MASK))))
46
47 #define ISP_L1PT_PTES           1024
48 #define ISP_L2PT_PTES           1024
49
50 #define ISP_PTR_TO_L1_IDX(x)    ((((x) & ISP_L1PT_MASK)) \
51                                         >> ISP_L1PT_OFFSET)
52
53 #define ISP_PTR_TO_L2_IDX(x)    ((((x) & ISP_L2PT_MASK)) \
54                                         >> ISP_L2PT_OFFSET)
55
56 #define ISP_PAGE_ALIGN(x)       (((x) + (ISP_PAGE_SIZE-1)) \
57                                         & ISP_PAGE_MASK)
58
59 #define ISP_PT_TO_VIRT(l1_idx, l2_idx, offset) do {\
60                 ((l1_idx) << ISP_L1PT_OFFSET) | \
61                 ((l2_idx) << ISP_L2PT_OFFSET) | \
62                 (offset)\
63 } while (0)
64
65 #define pgnr_to_size(pgnr)      ((pgnr) << ISP_PAGE_OFFSET)
66 #define size_to_pgnr_ceil(size) (((size) + (1 << ISP_PAGE_OFFSET) - 1)\
67                                                 >> ISP_PAGE_OFFSET)
68 #define size_to_pgnr_bottom(size)       ((size) >> ISP_PAGE_OFFSET)
69
70 struct isp_mmu;
71
72 struct isp_mmu_client {
73         /*
74          * const value
75          *
76          * @name:
77          *      driver name
78          * @pte_valid_mask:
79          *      should be 1 bit valid data, meaning the value should
80          *      be power of 2.
81          */
82         char *name;
83         unsigned int pte_valid_mask;
84         unsigned int null_pte;
85
86         /*
87          * set/get page directory base address (physical address).
88          *
89          * must be provided.
90          */
91         int (*set_pd_base) (struct isp_mmu *mmu,
92                         phys_addr_t pd_base);
93         unsigned int (*get_pd_base) (struct isp_mmu *mmu, phys_addr_t pd_base);
94         /*
95          * callback to flush tlb.
96          *
97          * tlb_flush_range will at least flush TLBs containing
98          * address mapping from addr to addr + size.
99          *
100          * tlb_flush_all will flush all TLBs.
101          *
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.
104          */
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,
109                                      phys_addr_t phys);
110         phys_addr_t (*pte_to_phys) (struct isp_mmu *mmu,
111                                     unsigned int pte);
112
113 };
114
115 struct isp_mmu {
116         struct isp_mmu_client *driver;
117         unsigned int l1_pte;
118         int l2_pgt_refcount[ISP_L1PT_PTES];
119         phys_addr_t base_address;
120
121         struct mutex pt_mutex;
122         struct kmem_cache *tbl_cache;
123 };
124
125 /* flags for PDE and PTE */
126 #define ISP_PTE_VALID_MASK(mmu) \
127         ((mmu)->driver->pte_valid_mask)
128
129 #define ISP_PTE_VALID(mmu, pte) \
130         ((pte) & ISP_PTE_VALID_MASK(mmu))
131
132 #define NULL_PAGE       ((phys_addr_t)(-1) & ISP_PAGE_MASK)
133 #define PAGE_VALID(page)        ((page) != NULL_PAGE)
134
135 /*
136  * init mmu with specific mmu driver.
137  */
138 int isp_mmu_init(struct isp_mmu *mmu, struct isp_mmu_client *driver);
139 /*
140  * cleanup all mmu related things.
141  */
142 void isp_mmu_exit(struct isp_mmu *mmu);
143
144 /*
145  * setup/remove address mapping for pgnr continous physical pages
146  * and isp_virt.
147  *
148  * map/unmap is mutex lock protected, and caller does not have
149  * to do lock/unlock operation.
150  *
151  * map/unmap will not flush tlb, and caller needs to deal with
152  * this itself.
153  */
154 int isp_mmu_map(struct isp_mmu *mmu, unsigned int isp_virt,
155                 phys_addr_t phys, unsigned int pgnr);
156
157 void isp_mmu_unmap(struct isp_mmu *mmu, unsigned int isp_virt,
158                    unsigned int pgnr);
159
160 static inline void isp_mmu_flush_tlb_all(struct isp_mmu *mmu)
161 {
162         if (mmu->driver && mmu->driver->tlb_flush_all)
163                 mmu->driver->tlb_flush_all(mmu);
164 }
165
166 #define isp_mmu_flush_tlb isp_mmu_flush_tlb_all
167
168 static inline void isp_mmu_flush_tlb_range(struct isp_mmu *mmu,
169                 unsigned int start, unsigned int size)
170 {
171         if (mmu->driver && mmu->driver->tlb_flush_range)
172                 mmu->driver->tlb_flush_range(mmu, start, size);
173 }
174
175 #endif /* ISP_MMU_H_ */