[go: nahoru, domu]

1af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU/*
2af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU * Tegra30 Memory Controller
3af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU *
4af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
5af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU *
6af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU * This program is free software; you can redistribute it and/or modify it
7af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU * under the terms and conditions of the GNU General Public License,
8af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU * version 2, as published by the Free Software Foundation.
9af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU *
10af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU * This program is distributed in the hope it will be useful, but WITHOUT
11af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU * more details.
14af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU *
15af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU * You should have received a copy of the GNU General Public License along with
16af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU * this program; if not, write to the Free Software Foundation, Inc.,
17af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU */
19af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
2006303c2e00701724acb95069ca46f87c998c4be1Thierry Reding#include <linux/err.h>
21af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#include <linux/kernel.h>
22af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#include <linux/module.h>
23af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#include <linux/ratelimit.h>
24af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#include <linux/platform_device.h>
25af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#include <linux/interrupt.h>
26af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#include <linux/io.h>
27af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
28af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define DRV_NAME "tegra30-mc"
29af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
30af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_INTSTATUS			0x0
31af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_INTMASK			0x4
32af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
33af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_INT_ERR_SHIFT		6
34af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_INT_ERR_MASK			(0x1f << MC_INT_ERR_SHIFT)
35af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_INT_DECERR_EMEM		BIT(MC_INT_ERR_SHIFT)
36af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_INT_SECURITY_VIOLATION	BIT(MC_INT_ERR_SHIFT + 2)
37af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_INT_ARBITRATION_EMEM		BIT(MC_INT_ERR_SHIFT + 3)
38af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_INT_INVALID_SMMU_PAGE	BIT(MC_INT_ERR_SHIFT + 4)
39af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
40af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_ERR_STATUS			0x8
41af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_ERR_ADR			0xc
42af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
43af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_ERR_TYPE_SHIFT		28
44af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_ERR_TYPE_MASK		(7 << MC_ERR_TYPE_SHIFT)
45af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_ERR_TYPE_DECERR_EMEM		2
46af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_ERR_TYPE_SECURITY_TRUSTZONE	3
47af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_ERR_TYPE_SECURITY_CARVEOUT	4
48af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_ERR_TYPE_INVALID_SMMU_PAGE	6
49af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
50af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_ERR_INVALID_SMMU_PAGE_SHIFT	25
51af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_ERR_INVALID_SMMU_PAGE_MASK	(7 << MC_ERR_INVALID_SMMU_PAGE_SHIFT)
52af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_ERR_RW_SHIFT			16
53af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_ERR_RW			BIT(MC_ERR_RW_SHIFT)
54af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_ERR_SECURITY			BIT(MC_ERR_RW_SHIFT + 1)
55af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
56af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define SECURITY_VIOLATION_TYPE		BIT(30)	/* 0=TRUSTZONE, 1=CARVEOUT */
57af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
58af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_CFG			0x90
59af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_OUTSTANDING_REQ	0x94
60af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_TIMING_RCD		0x98
61af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_TIMING_RP		0x9c
62af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_TIMING_RC		0xa0
63af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_TIMING_RAS		0xa4
64af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_TIMING_FAW		0xa8
65af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_TIMING_RRD		0xac
66af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_TIMING_RAP2PRE	0xb0
67af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_TIMING_WAP2PRE	0xb4
68af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_TIMING_R2R		0xb8
69af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_TIMING_W2W		0xbc
70af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_TIMING_R2W		0xc0
71af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_TIMING_W2R		0xc4
72af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
73af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_DA_TURNS		0xd0
74af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_DA_COVERS		0xd4
75af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_MISC0		0xd8
76af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_MISC1		0xdc
77af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
78af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_RING3_THROTTLE	0xe4
79af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_EMEM_ARB_OVERRIDE		0xe8
80af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
81af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_TIMING_CONTROL		0xfc
82af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
83af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define MC_CLIENT_ID_MASK		0x7f
84af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
85af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU#define NUM_MC_REG_BANKS		4
86af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
87af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYUstruct tegra30_mc {
88af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	void __iomem *regs[NUM_MC_REG_BANKS];
89af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	struct device *dev;
90af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	u32 ctx[0];
91af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU};
92af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
93af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYUstatic inline u32 mc_readl(struct tegra30_mc *mc, u32 offs)
94af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU{
95b37fd4154e758c7226fda663e2ea3a97c6e8c732Hiroshi DOYU	u32 val = 0;
96b37fd4154e758c7226fda663e2ea3a97c6e8c732Hiroshi DOYU
97af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	if (offs < 0x10)
98b37fd4154e758c7226fda663e2ea3a97c6e8c732Hiroshi DOYU		val = readl(mc->regs[0] + offs);
99e0f21e6d52cc245e7d4f7e02ca4b7b6571660ec2Axel Lin	else if (offs < 0x1f0)
100b37fd4154e758c7226fda663e2ea3a97c6e8c732Hiroshi DOYU		val = readl(mc->regs[1] + offs - 0x3c);
101e0f21e6d52cc245e7d4f7e02ca4b7b6571660ec2Axel Lin	else if (offs < 0x228)
102b37fd4154e758c7226fda663e2ea3a97c6e8c732Hiroshi DOYU		val = readl(mc->regs[2] + offs - 0x200);
103e0f21e6d52cc245e7d4f7e02ca4b7b6571660ec2Axel Lin	else if (offs < 0x400)
104b37fd4154e758c7226fda663e2ea3a97c6e8c732Hiroshi DOYU		val = readl(mc->regs[3] + offs - 0x284);
105b37fd4154e758c7226fda663e2ea3a97c6e8c732Hiroshi DOYU
106b37fd4154e758c7226fda663e2ea3a97c6e8c732Hiroshi DOYU	return val;
107af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU}
108af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
109af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYUstatic inline void mc_writel(struct tegra30_mc *mc, u32 val, u32 offs)
110af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU{
111e0f21e6d52cc245e7d4f7e02ca4b7b6571660ec2Axel Lin	if (offs < 0x10)
112af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		writel(val, mc->regs[0] + offs);
113e0f21e6d52cc245e7d4f7e02ca4b7b6571660ec2Axel Lin	else if (offs < 0x1f0)
114af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		writel(val, mc->regs[1] + offs - 0x3c);
115e0f21e6d52cc245e7d4f7e02ca4b7b6571660ec2Axel Lin	else if (offs < 0x228)
116af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		writel(val, mc->regs[2] + offs - 0x200);
117e0f21e6d52cc245e7d4f7e02ca4b7b6571660ec2Axel Lin	else if (offs < 0x400)
118af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		writel(val, mc->regs[3] + offs - 0x284);
119af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU}
120af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
121af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYUstatic const char * const tegra30_mc_client[] = {
122af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_ptcr",
123af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbr_display0a",
124af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbr_display0ab",
125af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbr_display0b",
126af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbr_display0bb",
127af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbr_display0c",
128af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbr_display0cb",
129af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbr_display1b",
130af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbr_display1bb",
131af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbr_eppup",
132af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbr_g2pr",
133af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbr_g2sr",
134af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbr_mpeunifbr",
135af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbr_viruv",
136af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_afir",
137af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_avpcarm7r",
138af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_displayhc",
139af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_displayhcb",
140af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_fdcdrd",
141af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_fdcdrd2",
142af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_g2dr",
143af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_hdar",
144af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_host1xdmar",
145af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_host1xr",
146af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_idxsrd",
147af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_idxsrd2",
148af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_mpe_ipred",
149af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_mpeamemrd",
150af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_mpecsrd",
151af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_ppcsahbdmar",
152af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_ppcsahbslvr",
153af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_satar",
154af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_texsrd",
155af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_texsrd2",
156af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_vdebsevr",
157af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_vdember",
158af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_vdemcer",
159af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_vdetper",
160af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_mpcorelpr",
161af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csr_mpcorer",
162af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbw_eppu",
163af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbw_eppv",
164af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbw_eppy",
165af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbw_mpeunifbw",
166af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbw_viwsb",
167af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbw_viwu",
168af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbw_viwv",
169af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"cbw_viwy",
170af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"ccw_g2dw",
171af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_afiw",
172af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_avpcarm7w",
173af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_fdcdwr",
174af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_fdcdwr2",
175af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_hdaw",
176af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_host1xw",
177af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_ispw",
178af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_mpcorelpw",
179af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_mpcorew",
180af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_mpecswr",
181af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_ppcsahbdmaw",
182af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_ppcsahbslvw",
183af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_sataw",
184af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_vdebsevw",
185af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_vdedbgw",
186af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_vdembew",
187af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	"csw_vdetpmw",
188af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU};
189af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
190af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYUstatic void tegra30_mc_decode(struct tegra30_mc *mc, int n)
191af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU{
192af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	u32 err, addr;
193af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	const char * const mc_int_err[] = {
194af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		"MC_DECERR",
195af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		"Unknown",
196af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		"MC_SECURITY_ERR",
197af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		"MC_ARBITRATION_EMEM",
198af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		"MC_SMMU_ERR",
199af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	};
200af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	const char * const err_type[] = {
201af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		"Unknown",
202af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		"Unknown",
203af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		"DECERR_EMEM",
204af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		"SECURITY_TRUSTZONE",
205af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		"SECURITY_CARVEOUT",
206af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		"Unknown",
207af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		"INVALID_SMMU_PAGE",
208af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		"Unknown",
209af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	};
210af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	char attr[6];
211af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	int cid, perm, type, idx;
212af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	const char *client = "Unknown";
213af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
214af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	idx = n - MC_INT_ERR_SHIFT;
215af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	if ((idx < 0) || (idx >= ARRAY_SIZE(mc_int_err)) || (idx == 1)) {
21690394482b807cb0a474fb387ed020603df14cfd0Hiroshi DOYU		dev_err_ratelimited(mc->dev, "Unknown interrupt status %08lx\n",
21790394482b807cb0a474fb387ed020603df14cfd0Hiroshi DOYU				    BIT(n));
218af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		return;
219af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	}
220af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
22136dd68319c7b56a76ed450b0e470067b5d74b9b2Tuomas Tynkkynen	err = mc_readl(mc, MC_ERR_STATUS);
222af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
223af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	type = (err & MC_ERR_TYPE_MASK) >> MC_ERR_TYPE_SHIFT;
224af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	perm = (err & MC_ERR_INVALID_SMMU_PAGE_MASK) >>
225af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		MC_ERR_INVALID_SMMU_PAGE_SHIFT;
226af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	if (type == MC_ERR_TYPE_INVALID_SMMU_PAGE)
227af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		sprintf(attr, "%c-%c-%c",
228af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU			(perm & BIT(2)) ? 'R' : '-',
229af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU			(perm & BIT(1)) ? 'W' : '-',
230af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU			(perm & BIT(0)) ? 'S' : '-');
231af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	else
232af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		attr[0] = '\0';
233af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
234af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	cid = err & MC_CLIENT_ID_MASK;
235af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	if (cid < ARRAY_SIZE(tegra30_mc_client))
236af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		client = tegra30_mc_client[cid];
237af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
23836dd68319c7b56a76ed450b0e470067b5d74b9b2Tuomas Tynkkynen	addr = mc_readl(mc, MC_ERR_ADR);
239af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
24090394482b807cb0a474fb387ed020603df14cfd0Hiroshi DOYU	dev_err_ratelimited(mc->dev, "%s (0x%08x): 0x%08x %s (%s %s %s %s)\n",
241af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU			   mc_int_err[idx], err, addr, client,
242af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU			   (err & MC_ERR_SECURITY) ? "secure" : "non-secure",
243af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU			   (err & MC_ERR_RW) ? "write" : "read",
244af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU			   err_type[type], attr);
245af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU}
246af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
247af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYUstatic const u32 tegra30_mc_ctx[] = {
248af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_CFG,
249af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_OUTSTANDING_REQ,
250af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_TIMING_RCD,
251af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_TIMING_RP,
252af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_TIMING_RC,
253af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_TIMING_RAS,
254af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_TIMING_FAW,
255af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_TIMING_RRD,
256af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_TIMING_RAP2PRE,
257af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_TIMING_WAP2PRE,
258af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_TIMING_R2R,
259af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_TIMING_W2W,
260af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_TIMING_R2W,
261af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_TIMING_W2R,
262af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_DA_TURNS,
263af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_DA_COVERS,
264af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_MISC0,
265af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_MISC1,
266af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_RING3_THROTTLE,
267af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_EMEM_ARB_OVERRIDE,
268af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	MC_INTMASK,
269af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU};
270af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
2719f7345b7a7cbf4c78a8161cba21de1772d5ad56eHiroshi Doyu#ifdef CONFIG_PM
272af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYUstatic int tegra30_mc_suspend(struct device *dev)
273af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU{
274af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	int i;
275af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	struct tegra30_mc *mc = dev_get_drvdata(dev);
276af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
277af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	for (i = 0; i < ARRAY_SIZE(tegra30_mc_ctx); i++)
278af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		mc->ctx[i] = mc_readl(mc, tegra30_mc_ctx[i]);
279af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	return 0;
280af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU}
281af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
282af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYUstatic int tegra30_mc_resume(struct device *dev)
283af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU{
284af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	int i;
285af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	struct tegra30_mc *mc = dev_get_drvdata(dev);
286af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
287af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	for (i = 0; i < ARRAY_SIZE(tegra30_mc_ctx); i++)
288af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		mc_writel(mc, mc->ctx[i], tegra30_mc_ctx[i]);
289af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
290af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	mc_writel(mc, 1, MC_TIMING_CONTROL);
291af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	/* Read-back to ensure that write reached */
292af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	mc_readl(mc, MC_TIMING_CONTROL);
293af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	return 0;
294af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU}
2959f7345b7a7cbf4c78a8161cba21de1772d5ad56eHiroshi Doyu#endif
296af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
297af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYUstatic UNIVERSAL_DEV_PM_OPS(tegra30_mc_pm,
298af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU			    tegra30_mc_suspend,
299af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU			    tegra30_mc_resume, NULL);
300af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
30127796aa0dce01661fedb5f3fa6b11db13f02a77fGreg Kroah-Hartmanstatic const struct of_device_id tegra30_mc_of_match[] = {
302af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	{ .compatible = "nvidia,tegra30-mc", },
303af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	{},
304af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU};
305af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
306af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYUstatic irqreturn_t tegra30_mc_isr(int irq, void *data)
307af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU{
308af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	u32 stat, mask, bit;
309af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	struct tegra30_mc *mc = data;
310af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
311af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	stat = mc_readl(mc, MC_INTSTATUS);
312af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	mask = mc_readl(mc, MC_INTMASK);
313af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	mask &= stat;
314af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	if (!mask)
315af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		return IRQ_NONE;
31636dd68319c7b56a76ed450b0e470067b5d74b9b2Tuomas Tynkkynen	while ((bit = ffs(mask)) != 0) {
317af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		tegra30_mc_decode(mc, bit - 1);
31836dd68319c7b56a76ed450b0e470067b5d74b9b2Tuomas Tynkkynen		mask &= ~BIT(bit - 1);
31936dd68319c7b56a76ed450b0e470067b5d74b9b2Tuomas Tynkkynen	}
32036dd68319c7b56a76ed450b0e470067b5d74b9b2Tuomas Tynkkynen
321af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	mc_writel(mc, stat, MC_INTSTATUS);
322af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	return IRQ_HANDLED;
323af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU}
324af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
32527796aa0dce01661fedb5f3fa6b11db13f02a77fGreg Kroah-Hartmanstatic int tegra30_mc_probe(struct platform_device *pdev)
326af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU{
327af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	struct resource *irq;
328af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	struct tegra30_mc *mc;
329af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	size_t bytes;
330af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	int err, i;
331af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	u32 intmask;
332af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
333af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	bytes = sizeof(*mc) + sizeof(u32) * ARRAY_SIZE(tegra30_mc_ctx);
334af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	mc = devm_kzalloc(&pdev->dev, bytes, GFP_KERNEL);
335af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	if (!mc)
336af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		return -ENOMEM;
337af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	mc->dev = &pdev->dev;
338af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
339af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	for (i = 0; i < ARRAY_SIZE(mc->regs); i++) {
340af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		struct resource *res;
341af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
342af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
34306303c2e00701724acb95069ca46f87c998c4be1Thierry Reding		mc->regs[i] = devm_ioremap_resource(&pdev->dev, res);
34406303c2e00701724acb95069ca46f87c998c4be1Thierry Reding		if (IS_ERR(mc->regs[i]))
34506303c2e00701724acb95069ca46f87c998c4be1Thierry Reding			return PTR_ERR(mc->regs[i]);
346af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	}
347af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
348af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
349af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	if (!irq)
350af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		return -ENODEV;
351af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	err = devm_request_irq(&pdev->dev, irq->start, tegra30_mc_isr,
352af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU			       IRQF_SHARED, dev_name(&pdev->dev), mc);
353af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	if (err)
354af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		return -ENODEV;
355af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
356af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	platform_set_drvdata(pdev, mc);
357af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
358af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	intmask = MC_INT_INVALID_SMMU_PAGE |
359af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION;
360af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	mc_writel(mc, intmask, MC_INTMASK);
361af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	return 0;
362af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU}
363af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
364af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYUstatic struct platform_driver tegra30_mc_driver = {
365af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	.probe = tegra30_mc_probe,
366af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	.driver = {
367af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		.name = DRV_NAME,
368af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		.owner = THIS_MODULE,
369af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		.of_match_table = tegra30_mc_of_match,
370af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU		.pm = &tegra30_mc_pm,
371af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU	},
372af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU};
373af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYUmodule_platform_driver(tegra30_mc_driver);
374af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYU
375af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYUMODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
376af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYUMODULE_DESCRIPTION("Tegra30 MC driver");
377af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYUMODULE_LICENSE("GPL v2");
378af4681097b23fe9c63a03d774de7c742fa3a920eHiroshi DOYUMODULE_ALIAS("platform:" DRV_NAME);
379