@@ -148,26 +148,12 @@ static u32 lv2ent_offset(sysmmu_iova_t iova)
148148#define MAKE_MMU_VER (maj , min ) ((((maj) & 0xF) << 7) | ((min) & 0x7F))
149149
150150/* v1.x - v3.x registers */
151- #define REG_MMU_FLUSH 0x00C
152- #define REG_MMU_FLUSH_ENTRY 0x010
153- #define REG_PT_BASE_ADDR 0x014
154- #define REG_INT_STATUS 0x018
155- #define REG_INT_CLEAR 0x01C
156-
157151#define REG_PAGE_FAULT_ADDR 0x024
158152#define REG_AW_FAULT_ADDR 0x028
159153#define REG_AR_FAULT_ADDR 0x02C
160154#define REG_DEFAULT_SLAVE_ADDR 0x030
161155
162156/* v5.x registers */
163- #define REG_V5_PT_BASE_PFN 0x00C
164- #define REG_V5_MMU_FLUSH_ALL 0x010
165- #define REG_V5_MMU_FLUSH_ENTRY 0x014
166- #define REG_V5_MMU_FLUSH_RANGE 0x018
167- #define REG_V5_MMU_FLUSH_START 0x020
168- #define REG_V5_MMU_FLUSH_END 0x024
169- #define REG_V5_INT_STATUS 0x060
170- #define REG_V5_INT_CLEAR 0x064
171157#define REG_V5_FAULT_AR_VA 0x070
172158#define REG_V5_FAULT_AW_VA 0x080
173159
@@ -250,6 +236,21 @@ struct exynos_iommu_domain {
250236 struct iommu_domain domain ; /* generic domain data structure */
251237};
252238
239+ /*
240+ * SysMMU version specific data. Contains offsets for the registers which can
241+ * be found in different SysMMU variants, but have different offset values.
242+ */
243+ struct sysmmu_variant {
244+ u32 pt_base ; /* page table base address (physical) */
245+ u32 flush_all ; /* invalidate all TLB entries */
246+ u32 flush_entry ; /* invalidate specific TLB entry */
247+ u32 flush_range ; /* invalidate TLB entries in specified range */
248+ u32 flush_start ; /* start address of range invalidation */
249+ u32 flush_end ; /* end address of range invalidation */
250+ u32 int_status ; /* interrupt status information */
251+ u32 int_clear ; /* clear the interrupt */
252+ };
253+
253254/*
254255 * This structure hold all data of a single SYSMMU controller, this includes
255256 * hw resources like registers and clocks, pointers and list nodes to connect
@@ -274,6 +275,30 @@ struct sysmmu_drvdata {
274275 unsigned int version ; /* our version */
275276
276277 struct iommu_device iommu ; /* IOMMU core handle */
278+ const struct sysmmu_variant * variant ; /* version specific data */
279+ };
280+
281+ #define SYSMMU_REG (data , reg ) ((data)->sfrbase + (data)->variant->reg)
282+
283+ /* SysMMU v1..v3 */
284+ static const struct sysmmu_variant sysmmu_v1_variant = {
285+ .flush_all = 0x0c ,
286+ .flush_entry = 0x10 ,
287+ .pt_base = 0x14 ,
288+ .int_status = 0x18 ,
289+ .int_clear = 0x1c ,
290+ };
291+
292+ /* SysMMU v5 */
293+ static const struct sysmmu_variant sysmmu_v5_variant = {
294+ .pt_base = 0x0c ,
295+ .flush_all = 0x10 ,
296+ .flush_entry = 0x14 ,
297+ .flush_range = 0x18 ,
298+ .flush_start = 0x20 ,
299+ .flush_end = 0x24 ,
300+ .int_status = 0x60 ,
301+ .int_clear = 0x64 ,
277302};
278303
279304static struct exynos_iommu_domain * to_exynos_domain (struct iommu_domain * dom )
@@ -304,44 +329,38 @@ static bool sysmmu_block(struct sysmmu_drvdata *data)
304329
305330static void __sysmmu_tlb_invalidate (struct sysmmu_drvdata * data )
306331{
307- if (MMU_MAJ_VER (data -> version ) < 5 )
308- writel (0x1 , data -> sfrbase + REG_MMU_FLUSH );
309- else
310- writel (0x1 , data -> sfrbase + REG_V5_MMU_FLUSH_ALL );
332+ writel (0x1 , SYSMMU_REG (data , flush_all ));
311333}
312334
313335static void __sysmmu_tlb_invalidate_entry (struct sysmmu_drvdata * data ,
314336 sysmmu_iova_t iova , unsigned int num_inv )
315337{
316338 unsigned int i ;
317339
318- if (MMU_MAJ_VER (data -> version ) < 5 ) {
340+ if (MMU_MAJ_VER (data -> version ) < 5 || num_inv == 1 ) {
319341 for (i = 0 ; i < num_inv ; i ++ ) {
320342 writel ((iova & SPAGE_MASK ) | 1 ,
321- data -> sfrbase + REG_MMU_FLUSH_ENTRY );
343+ SYSMMU_REG ( data , flush_entry ) );
322344 iova += SPAGE_SIZE ;
323345 }
324346 } else {
325- if (num_inv == 1 ) {
326- writel ((iova & SPAGE_MASK ) | 1 ,
327- data -> sfrbase + REG_V5_MMU_FLUSH_ENTRY );
328- } else {
329- writel ((iova & SPAGE_MASK ),
330- data -> sfrbase + REG_V5_MMU_FLUSH_START );
331- writel ((iova & SPAGE_MASK ) + (num_inv - 1 ) * SPAGE_SIZE ,
332- data -> sfrbase + REG_V5_MMU_FLUSH_END );
333- writel (1 , data -> sfrbase + REG_V5_MMU_FLUSH_RANGE );
334- }
347+ writel (iova & SPAGE_MASK , SYSMMU_REG (data , flush_start ));
348+ writel ((iova & SPAGE_MASK ) + (num_inv - 1 ) * SPAGE_SIZE ,
349+ SYSMMU_REG (data , flush_end ));
350+ writel (0x1 , SYSMMU_REG (data , flush_range ));
335351 }
336352}
337353
338354static void __sysmmu_set_ptbase (struct sysmmu_drvdata * data , phys_addr_t pgd )
339355{
356+ u32 pt_base ;
357+
340358 if (MMU_MAJ_VER (data -> version ) < 5 )
341- writel ( pgd , data -> sfrbase + REG_PT_BASE_ADDR ) ;
359+ pt_base = pgd ;
342360 else
343- writel ( pgd >> SPAGE_ORDER , data -> sfrbase + REG_V5_PT_BASE_PFN ) ;
361+ pt_base = pgd >> SPAGE_ORDER ;
344362
363+ writel (pt_base , SYSMMU_REG (data , pt_base ));
345364 __sysmmu_tlb_invalidate (data );
346365}
347366
@@ -378,6 +397,11 @@ static void __sysmmu_get_version(struct sysmmu_drvdata *data)
378397 dev_dbg (data -> sysmmu , "hardware version: %d.%d\n" ,
379398 MMU_MAJ_VER (data -> version ), MMU_MIN_VER (data -> version ));
380399
400+ if (MMU_MAJ_VER (data -> version ) < 5 )
401+ data -> variant = & sysmmu_v1_variant ;
402+ else
403+ data -> variant = & sysmmu_v5_variant ;
404+
381405 __sysmmu_disable_clocks (data );
382406}
383407
@@ -405,19 +429,14 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
405429 const struct sysmmu_fault_info * finfo ;
406430 unsigned int i , n , itype ;
407431 sysmmu_iova_t fault_addr ;
408- unsigned short reg_status , reg_clear ;
409432 int ret = - ENOSYS ;
410433
411434 WARN_ON (!data -> active );
412435
413436 if (MMU_MAJ_VER (data -> version ) < 5 ) {
414- reg_status = REG_INT_STATUS ;
415- reg_clear = REG_INT_CLEAR ;
416437 finfo = sysmmu_faults ;
417438 n = ARRAY_SIZE (sysmmu_faults );
418439 } else {
419- reg_status = REG_V5_INT_STATUS ;
420- reg_clear = REG_V5_INT_CLEAR ;
421440 finfo = sysmmu_v5_faults ;
422441 n = ARRAY_SIZE (sysmmu_v5_faults );
423442 }
@@ -426,7 +445,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
426445
427446 clk_enable (data -> clk_master );
428447
429- itype = __ffs (readl (data -> sfrbase + reg_status ));
448+ itype = __ffs (readl (SYSMMU_REG ( data , int_status ) ));
430449 for (i = 0 ; i < n ; i ++ , finfo ++ )
431450 if (finfo -> bit == itype )
432451 break ;
@@ -443,7 +462,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
443462 /* fault is not recovered by fault handler */
444463 BUG_ON (ret != 0 );
445464
446- writel (1 << itype , data -> sfrbase + reg_clear );
465+ writel (1 << itype , SYSMMU_REG ( data , int_clear ) );
447466
448467 sysmmu_unblock (data );
449468
@@ -622,6 +641,8 @@ static int exynos_sysmmu_probe(struct platform_device *pdev)
622641 data -> sysmmu = dev ;
623642 spin_lock_init (& data -> lock );
624643
644+ __sysmmu_get_version (data );
645+
625646 ret = iommu_device_sysfs_add (& data -> iommu , & pdev -> dev , NULL ,
626647 dev_name (data -> sysmmu ));
627648 if (ret )
@@ -633,7 +654,6 @@ static int exynos_sysmmu_probe(struct platform_device *pdev)
633654
634655 platform_set_drvdata (pdev , data );
635656
636- __sysmmu_get_version (data );
637657 if (PG_ENT_SHIFT < 0 ) {
638658 if (MMU_MAJ_VER (data -> version ) < 5 ) {
639659 PG_ENT_SHIFT = SYSMMU_PG_ENT_SHIFT ;
0 commit comments