Skip to content

Commit 740a01e

Browse files
mszyprowjoergroedel
authored andcommitted
iommu/exynos: Add support for v5 SYSMMU
This patch adds support for v5 of SYSMMU controller, found in Samsung Exynos 5433 SoCs. The main difference of v5 is support for 36-bit physical address space and some changes in register layout and core clocks hanging. This patch also adds support for ARM64 architecture, which is used by Exynos 5433 SoCs. Signed-off-by: Marek Szyprowski <[email protected]> Signed-off-by: Joerg Roedel <[email protected]>
1 parent e680270 commit 740a01e

3 files changed

Lines changed: 143 additions & 51 deletions

File tree

Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ Required properties:
3535
- interrupts: An interrupt specifier for interrupt signal of System MMU,
3636
according to the format defined by a particular interrupt
3737
controller.
38-
- clock-names: Should be "sysmmu" if the System MMU is needed to gate its clock.
38+
- clock-names: Should be "sysmmu" or a pair of "aclk" and "pclk" to gate
39+
SYSMMU core clocks.
3940
Optional "master" if the clock to the System MMU is gated by
40-
another gate clock other than "sysmmu" (usually main gate clock
41+
another gate clock other core (usually main gate clock
4142
of peripheral device this SYSMMU belongs to).
4243
- clocks: Phandles for respective clocks described by clock-names.
4344
- power-domains: Required if the System MMU is needed to gate its power.

drivers/iommu/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ config TEGRA_IOMMU_SMMU
243243

244244
config EXYNOS_IOMMU
245245
bool "Exynos IOMMU Support"
246-
depends on ARCH_EXYNOS && ARM && MMU
246+
depends on ARCH_EXYNOS && MMU
247247
select IOMMU_API
248248
select ARM_DMA_USE_IOMMU
249249
help

drivers/iommu/exynos-iommu.c

Lines changed: 139 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
/* linux/drivers/iommu/exynos_iommu.c
2-
*
3-
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
1+
/*
2+
* Copyright (c) 2011,2016 Samsung Electronics Co., Ltd.
43
* http://www.samsung.com
54
*
65
* This program is free software; you can redistribute it and/or modify
@@ -55,17 +54,25 @@ typedef u32 sysmmu_pte_t;
5554
#define lv2ent_small(pent) ((*(pent) & 2) == 2)
5655
#define lv2ent_large(pent) ((*(pent) & 3) == 1)
5756

58-
static u32 sysmmu_page_offset(sysmmu_iova_t iova, u32 size)
59-
{
60-
return iova & (size - 1);
61-
}
62-
63-
#define section_phys(sent) (*(sent) & SECT_MASK)
64-
#define section_offs(iova) sysmmu_page_offset((iova), SECT_SIZE)
65-
#define lpage_phys(pent) (*(pent) & LPAGE_MASK)
66-
#define lpage_offs(iova) sysmmu_page_offset((iova), LPAGE_SIZE)
67-
#define spage_phys(pent) (*(pent) & SPAGE_MASK)
68-
#define spage_offs(iova) sysmmu_page_offset((iova), SPAGE_SIZE)
57+
/*
58+
* v1.x - v3.x SYSMMU supports 32bit physical and 32bit virtual address spaces
59+
* v5.0 introduced support for 36bit physical address space by shifting
60+
* all page entry values by 4 bits.
61+
* All SYSMMU controllers in the system support the address spaces of the same
62+
* size, so PG_ENT_SHIFT can be initialized on first SYSMMU probe to proper
63+
* value (0 or 4).
64+
*/
65+
static short PG_ENT_SHIFT = -1;
66+
#define SYSMMU_PG_ENT_SHIFT 0
67+
#define SYSMMU_V5_PG_ENT_SHIFT 4
68+
69+
#define sect_to_phys(ent) (((phys_addr_t) ent) << PG_ENT_SHIFT)
70+
#define section_phys(sent) (sect_to_phys(*(sent)) & SECT_MASK)
71+
#define section_offs(iova) (iova & (SECT_SIZE - 1))
72+
#define lpage_phys(pent) (sect_to_phys(*(pent)) & LPAGE_MASK)
73+
#define lpage_offs(iova) (iova & (LPAGE_SIZE - 1))
74+
#define spage_phys(pent) (sect_to_phys(*(pent)) & SPAGE_MASK)
75+
#define spage_offs(iova) (iova & (SPAGE_SIZE - 1))
6976

7077
#define NUM_LV1ENTRIES 4096
7178
#define NUM_LV2ENTRIES (SECT_SIZE / SPAGE_SIZE)
@@ -84,28 +91,36 @@ static u32 lv2ent_offset(sysmmu_iova_t iova)
8491
#define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(sysmmu_pte_t))
8592

8693
#define SPAGES_PER_LPAGE (LPAGE_SIZE / SPAGE_SIZE)
94+
#define lv2table_base(sent) (sect_to_phys(*(sent) & 0xFFFFFFC0))
8795

88-
#define lv2table_base(sent) (*(sent) & 0xFFFFFC00)
89-
90-
#define mk_lv1ent_sect(pa) ((pa) | 2)
91-
#define mk_lv1ent_page(pa) ((pa) | 1)
92-
#define mk_lv2ent_lpage(pa) ((pa) | 1)
93-
#define mk_lv2ent_spage(pa) ((pa) | 2)
96+
#define mk_lv1ent_sect(pa) ((pa >> PG_ENT_SHIFT) | 2)
97+
#define mk_lv1ent_page(pa) ((pa >> PG_ENT_SHIFT) | 1)
98+
#define mk_lv2ent_lpage(pa) ((pa >> PG_ENT_SHIFT) | 1)
99+
#define mk_lv2ent_spage(pa) ((pa >> PG_ENT_SHIFT) | 2)
94100

95101
#define CTRL_ENABLE 0x5
96102
#define CTRL_BLOCK 0x7
97103
#define CTRL_DISABLE 0x0
98104

99105
#define CFG_LRU 0x1
100106
#define CFG_QOS(n) ((n & 0xF) << 7)
101-
#define CFG_MASK 0x0150FFFF /* Selecting bit 0-15, 20, 22 and 24 */
102107
#define CFG_ACGEN (1 << 24) /* System MMU 3.3 only */
103108
#define CFG_SYSSEL (1 << 22) /* System MMU 3.2 only */
104109
#define CFG_FLPDCACHE (1 << 20) /* System MMU 3.2+ only */
105110

111+
/* common registers */
106112
#define REG_MMU_CTRL 0x000
107113
#define REG_MMU_CFG 0x004
108114
#define REG_MMU_STATUS 0x008
115+
#define REG_MMU_VERSION 0x034
116+
117+
#define MMU_MAJ_VER(val) ((val) >> 7)
118+
#define MMU_MIN_VER(val) ((val) & 0x7F)
119+
#define MMU_RAW_VER(reg) (((reg) >> 21) & ((1 << 11) - 1)) /* 11 bits */
120+
121+
#define MAKE_MMU_VER(maj, min) ((((maj) & 0xF) << 7) | ((min) & 0x7F))
122+
123+
/* v1.x - v3.x registers */
109124
#define REG_MMU_FLUSH 0x00C
110125
#define REG_MMU_FLUSH_ENTRY 0x010
111126
#define REG_PT_BASE_ADDR 0x014
@@ -117,18 +132,14 @@ static u32 lv2ent_offset(sysmmu_iova_t iova)
117132
#define REG_AR_FAULT_ADDR 0x02C
118133
#define REG_DEFAULT_SLAVE_ADDR 0x030
119134

120-
#define REG_MMU_VERSION 0x034
121-
122-
#define MMU_MAJ_VER(val) ((val) >> 7)
123-
#define MMU_MIN_VER(val) ((val) & 0x7F)
124-
#define MMU_RAW_VER(reg) (((reg) >> 21) & ((1 << 11) - 1)) /* 11 bits */
125-
126-
#define MAKE_MMU_VER(maj, min) ((((maj) & 0xF) << 7) | ((min) & 0x7F))
127-
128-
#define REG_PB0_SADDR 0x04C
129-
#define REG_PB0_EADDR 0x050
130-
#define REG_PB1_SADDR 0x054
131-
#define REG_PB1_EADDR 0x058
135+
/* v5.x registers */
136+
#define REG_V5_PT_BASE_PFN 0x00C
137+
#define REG_V5_MMU_FLUSH_ALL 0x010
138+
#define REG_V5_MMU_FLUSH_ENTRY 0x014
139+
#define REG_V5_INT_STATUS 0x060
140+
#define REG_V5_INT_CLEAR 0x064
141+
#define REG_V5_FAULT_AR_VA 0x070
142+
#define REG_V5_FAULT_AW_VA 0x080
132143

133144
#define has_sysmmu(dev) (dev->archdata.iommu != NULL)
134145

@@ -169,6 +180,19 @@ static const struct sysmmu_fault_info sysmmu_faults[] = {
169180
{ 7, REG_AW_FAULT_ADDR, "AW ACCESS PROTECTION", IOMMU_FAULT_WRITE },
170181
};
171182

183+
static const struct sysmmu_fault_info sysmmu_v5_faults[] = {
184+
{ 0, REG_V5_FAULT_AR_VA, "AR PTW", IOMMU_FAULT_READ },
185+
{ 1, REG_V5_FAULT_AR_VA, "AR PAGE", IOMMU_FAULT_READ },
186+
{ 2, REG_V5_FAULT_AR_VA, "AR MULTI-HIT", IOMMU_FAULT_READ },
187+
{ 3, REG_V5_FAULT_AR_VA, "AR ACCESS PROTECTION", IOMMU_FAULT_READ },
188+
{ 4, REG_V5_FAULT_AR_VA, "AR SECURITY PROTECTION", IOMMU_FAULT_READ },
189+
{ 16, REG_V5_FAULT_AW_VA, "AW PTW", IOMMU_FAULT_WRITE },
190+
{ 17, REG_V5_FAULT_AW_VA, "AW PAGE", IOMMU_FAULT_WRITE },
191+
{ 18, REG_V5_FAULT_AW_VA, "AW MULTI-HIT", IOMMU_FAULT_WRITE },
192+
{ 19, REG_V5_FAULT_AW_VA, "AW ACCESS PROTECTION", IOMMU_FAULT_WRITE },
193+
{ 20, REG_V5_FAULT_AW_VA, "AW SECURITY PROTECTION", IOMMU_FAULT_WRITE },
194+
};
195+
172196
/*
173197
* This structure is attached to dev.archdata.iommu of the master device
174198
* on device add, contains a list of SYSMMU controllers defined by device tree,
@@ -205,6 +229,8 @@ struct sysmmu_drvdata {
205229
struct device *master; /* master device (owner) */
206230
void __iomem *sfrbase; /* our registers */
207231
struct clk *clk; /* SYSMMU's clock */
232+
struct clk *aclk; /* SYSMMU's aclk clock */
233+
struct clk *pclk; /* SYSMMU's pclk clock */
208234
struct clk *clk_master; /* master's device clock */
209235
int activations; /* number of calls to sysmmu_enable */
210236
spinlock_t lock; /* lock for modyfying state */
@@ -262,7 +288,10 @@ static bool sysmmu_block(struct sysmmu_drvdata *data)
262288

263289
static void __sysmmu_tlb_invalidate(struct sysmmu_drvdata *data)
264290
{
265-
__raw_writel(0x1, data->sfrbase + REG_MMU_FLUSH);
291+
if (MMU_MAJ_VER(data->version) < 5)
292+
__raw_writel(0x1, data->sfrbase + REG_MMU_FLUSH);
293+
else
294+
__raw_writel(0x1, data->sfrbase + REG_V5_MMU_FLUSH_ALL);
266295
}
267296

268297
static void __sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data,
@@ -271,15 +300,23 @@ static void __sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data,
271300
unsigned int i;
272301

273302
for (i = 0; i < num_inv; i++) {
274-
__raw_writel((iova & SPAGE_MASK) | 1,
275-
data->sfrbase + REG_MMU_FLUSH_ENTRY);
303+
if (MMU_MAJ_VER(data->version) < 5)
304+
__raw_writel((iova & SPAGE_MASK) | 1,
305+
data->sfrbase + REG_MMU_FLUSH_ENTRY);
306+
else
307+
__raw_writel((iova & SPAGE_MASK) | 1,
308+
data->sfrbase + REG_V5_MMU_FLUSH_ENTRY);
276309
iova += SPAGE_SIZE;
277310
}
278311
}
279312

280313
static void __sysmmu_set_ptbase(struct sysmmu_drvdata *data, phys_addr_t pgd)
281314
{
282-
__raw_writel(pgd, data->sfrbase + REG_PT_BASE_ADDR);
315+
if (MMU_MAJ_VER(data->version) < 5)
316+
__raw_writel(pgd, data->sfrbase + REG_PT_BASE_ADDR);
317+
else
318+
__raw_writel(pgd >> PAGE_SHIFT,
319+
data->sfrbase + REG_V5_PT_BASE_PFN);
283320

284321
__sysmmu_tlb_invalidate(data);
285322
}
@@ -290,6 +327,8 @@ static void __sysmmu_get_version(struct sysmmu_drvdata *data)
290327

291328
clk_enable(data->clk_master);
292329
clk_enable(data->clk);
330+
clk_enable(data->pclk);
331+
clk_enable(data->aclk);
293332

294333
ver = __raw_readl(data->sfrbase + REG_MMU_VERSION);
295334

@@ -302,6 +341,8 @@ static void __sysmmu_get_version(struct sysmmu_drvdata *data)
302341
dev_dbg(data->sysmmu, "hardware version: %d.%d\n",
303342
MMU_MAJ_VER(data->version), MMU_MIN_VER(data->version));
304343

344+
clk_disable(data->aclk);
345+
clk_disable(data->pclk);
305346
clk_disable(data->clk);
306347
clk_disable(data->clk_master);
307348
}
@@ -326,19 +367,31 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
326367
{
327368
/* SYSMMU is in blocked state when interrupt occurred. */
328369
struct sysmmu_drvdata *data = dev_id;
329-
const struct sysmmu_fault_info *finfo = sysmmu_faults;
330-
int i, n = ARRAY_SIZE(sysmmu_faults);
331-
unsigned int itype;
370+
const struct sysmmu_fault_info *finfo;
371+
unsigned int i, n, itype;
332372
sysmmu_iova_t fault_addr = -1;
373+
unsigned short reg_status, reg_clear;
333374
int ret = -ENOSYS;
334375

335376
WARN_ON(!is_sysmmu_active(data));
336377

378+
if (MMU_MAJ_VER(data->version) < 5) {
379+
reg_status = REG_INT_STATUS;
380+
reg_clear = REG_INT_CLEAR;
381+
finfo = sysmmu_faults;
382+
n = ARRAY_SIZE(sysmmu_faults);
383+
} else {
384+
reg_status = REG_V5_INT_STATUS;
385+
reg_clear = REG_V5_INT_CLEAR;
386+
finfo = sysmmu_v5_faults;
387+
n = ARRAY_SIZE(sysmmu_v5_faults);
388+
}
389+
337390
spin_lock(&data->lock);
338391

339392
clk_enable(data->clk_master);
340393

341-
itype = __ffs(__raw_readl(data->sfrbase + REG_INT_STATUS));
394+
itype = __ffs(__raw_readl(data->sfrbase + reg_status));
342395
for (i = 0; i < n; i++, finfo++)
343396
if (finfo->bit == itype)
344397
break;
@@ -355,7 +408,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
355408
/* fault is not recovered by fault handler */
356409
BUG_ON(ret != 0);
357410

358-
__raw_writel(1 << itype, data->sfrbase + REG_INT_CLEAR);
411+
__raw_writel(1 << itype, data->sfrbase + reg_clear);
359412

360413
sysmmu_unblock(data);
361414

@@ -373,6 +426,8 @@ static void __sysmmu_disable_nocount(struct sysmmu_drvdata *data)
373426
__raw_writel(CTRL_DISABLE, data->sfrbase + REG_MMU_CTRL);
374427
__raw_writel(0, data->sfrbase + REG_MMU_CFG);
375428

429+
clk_disable(data->aclk);
430+
clk_disable(data->pclk);
376431
clk_disable(data->clk);
377432
clk_disable(data->clk_master);
378433
}
@@ -421,6 +476,8 @@ static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data)
421476
{
422477
clk_enable(data->clk_master);
423478
clk_enable(data->clk);
479+
clk_enable(data->pclk);
480+
clk_enable(data->aclk);
424481

425482
__raw_writel(CTRL_BLOCK, data->sfrbase + REG_MMU_CTRL);
426483

@@ -544,22 +601,47 @@ static int __init exynos_sysmmu_probe(struct platform_device *pdev)
544601
}
545602

546603
data->clk = devm_clk_get(dev, "sysmmu");
547-
if (IS_ERR(data->clk)) {
548-
dev_err(dev, "Failed to get clock!\n");
549-
return PTR_ERR(data->clk);
550-
} else {
604+
if (!IS_ERR(data->clk)) {
551605
ret = clk_prepare(data->clk);
552606
if (ret) {
553607
dev_err(dev, "Failed to prepare clk\n");
554608
return ret;
555609
}
610+
} else {
611+
data->clk = NULL;
612+
}
613+
614+
data->aclk = devm_clk_get(dev, "aclk");
615+
if (!IS_ERR(data->aclk)) {
616+
ret = clk_prepare(data->aclk);
617+
if (ret) {
618+
dev_err(dev, "Failed to prepare aclk\n");
619+
return ret;
620+
}
621+
} else {
622+
data->aclk = NULL;
623+
}
624+
625+
data->pclk = devm_clk_get(dev, "pclk");
626+
if (!IS_ERR(data->pclk)) {
627+
ret = clk_prepare(data->pclk);
628+
if (ret) {
629+
dev_err(dev, "Failed to prepare pclk\n");
630+
return ret;
631+
}
632+
} else {
633+
data->pclk = NULL;
634+
}
635+
636+
if (!data->clk && (!data->aclk || !data->pclk)) {
637+
dev_err(dev, "Failed to get device clock(s)!\n");
638+
return -ENOSYS;
556639
}
557640

558641
data->clk_master = devm_clk_get(dev, "master");
559642
if (!IS_ERR(data->clk_master)) {
560643
ret = clk_prepare(data->clk_master);
561644
if (ret) {
562-
clk_unprepare(data->clk);
563645
dev_err(dev, "Failed to prepare master's clk\n");
564646
return ret;
565647
}
@@ -573,6 +655,13 @@ static int __init exynos_sysmmu_probe(struct platform_device *pdev)
573655
platform_set_drvdata(pdev, data);
574656

575657
__sysmmu_get_version(data);
658+
if (PG_ENT_SHIFT < 0) {
659+
if (MMU_MAJ_VER(data->version) < 5)
660+
PG_ENT_SHIFT = SYSMMU_PG_ENT_SHIFT;
661+
else
662+
PG_ENT_SHIFT = SYSMMU_V5_PG_ENT_SHIFT;
663+
}
664+
576665
pm_runtime_enable(dev);
577666

578667
return 0;
@@ -637,6 +726,8 @@ static struct iommu_domain *exynos_iommu_domain_alloc(unsigned type)
637726
dma_addr_t handle;
638727
int i;
639728

729+
/* Check if correct PTE offsets are initialized */
730+
BUG_ON(PG_ENT_SHIFT < 0 || !dma_dev);
640731

641732
domain = kzalloc(sizeof(*domain), GFP_KERNEL);
642733
if (!domain)
@@ -816,7 +907,7 @@ static sysmmu_pte_t *alloc_lv2entry(struct exynos_iommu_domain *domain,
816907
bool need_flush_flpd_cache = lv1ent_zero(sent);
817908

818909
pent = kmem_cache_zalloc(lv2table_kmem_cache, GFP_ATOMIC);
819-
BUG_ON((unsigned int)pent & (LV2TABLE_SIZE - 1));
910+
BUG_ON((phys_addr_t)pent & (LV2TABLE_SIZE - 1));
820911
if (!pent)
821912
return ERR_PTR(-ENOMEM);
822913

0 commit comments

Comments
 (0)