diff options
author | Stephane Viau <sviau@codeaurora.org> | 2014-11-18 12:49:48 -0500 |
---|---|---|
committer | Rob Clark <robdclark@gmail.com> | 2014-11-21 08:57:17 -0500 |
commit | 2e362e1772b8978428f087007fc4d6c4990efd41 (patch) | |
tree | 38db35194a6b1d7829c573d2bc14ef9d427616e3 | |
parent | bfcdfb0e62639732339c85371a8c07e915bf0941 (diff) |
drm/msm/mdp5: introduce mdp5_cfg module
The hardware configuration modification from a version to another
is quite consequent. Introducing a configuration module
(mdp5_cfg) may make things more clear and easier to access when a
new hardware version comes up.
Signed-off-by: Stephane Viau <sviau@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
-rw-r--r-- | drivers/gpu/drm/msm/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c | 215 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h | 88 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 211 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h | 39 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c | 9 |
6 files changed, 354 insertions, 209 deletions
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 0d96132df059..dda38529dd56 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile | |||
@@ -25,6 +25,7 @@ msm-y := \ | |||
25 | mdp/mdp4/mdp4_irq.o \ | 25 | mdp/mdp4/mdp4_irq.o \ |
26 | mdp/mdp4/mdp4_kms.o \ | 26 | mdp/mdp4/mdp4_kms.o \ |
27 | mdp/mdp4/mdp4_plane.o \ | 27 | mdp/mdp4/mdp4_plane.o \ |
28 | mdp/mdp5/mdp5_cfg.o \ | ||
28 | mdp/mdp5/mdp5_crtc.o \ | 29 | mdp/mdp5/mdp5_crtc.o \ |
29 | mdp/mdp5/mdp5_encoder.o \ | 30 | mdp/mdp5/mdp5_encoder.o \ |
30 | mdp/mdp5/mdp5_irq.o \ | 31 | mdp/mdp5/mdp5_irq.o \ |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c new file mode 100644 index 000000000000..62e77d1d3c59 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c | |||
@@ -0,0 +1,215 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 The Linux Foundation. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 and | ||
6 | * only version 2 as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #include "mdp5_kms.h" | ||
15 | #include "mdp5_cfg.h" | ||
16 | |||
17 | struct mdp5_cfg_handler { | ||
18 | int revision; | ||
19 | struct mdp5_cfg config; | ||
20 | }; | ||
21 | |||
22 | /* mdp5_cfg must be exposed (used in mdp5.xml.h) */ | ||
23 | const struct mdp5_cfg_hw *mdp5_cfg = NULL; | ||
24 | |||
25 | const struct mdp5_cfg_hw msm8x74_config = { | ||
26 | .name = "msm8x74", | ||
27 | .smp = { | ||
28 | .mmb_count = 22, | ||
29 | .mmb_size = 4096, | ||
30 | }, | ||
31 | .ctl = { | ||
32 | .count = 5, | ||
33 | .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, | ||
34 | }, | ||
35 | .pipe_vig = { | ||
36 | .count = 3, | ||
37 | .base = { 0x01200, 0x01600, 0x01a00 }, | ||
38 | }, | ||
39 | .pipe_rgb = { | ||
40 | .count = 3, | ||
41 | .base = { 0x01e00, 0x02200, 0x02600 }, | ||
42 | }, | ||
43 | .pipe_dma = { | ||
44 | .count = 2, | ||
45 | .base = { 0x02a00, 0x02e00 }, | ||
46 | }, | ||
47 | .lm = { | ||
48 | .count = 5, | ||
49 | .base = { 0x03200, 0x03600, 0x03a00, 0x03e00, 0x04200 }, | ||
50 | .nb_stages = 5, | ||
51 | }, | ||
52 | .dspp = { | ||
53 | .count = 3, | ||
54 | .base = { 0x04600, 0x04a00, 0x04e00 }, | ||
55 | }, | ||
56 | .ad = { | ||
57 | .count = 2, | ||
58 | .base = { 0x13100, 0x13300 }, /* NOTE: no ad in v1.0 */ | ||
59 | }, | ||
60 | .intf = { | ||
61 | .count = 4, | ||
62 | .base = { 0x12500, 0x12700, 0x12900, 0x12b00 }, | ||
63 | }, | ||
64 | .max_clk = 200000000, | ||
65 | }; | ||
66 | |||
67 | const struct mdp5_cfg_hw apq8084_config = { | ||
68 | .name = "apq8084", | ||
69 | .smp = { | ||
70 | .mmb_count = 44, | ||
71 | .mmb_size = 8192, | ||
72 | .reserved_state[0] = GENMASK(7, 0), /* first 8 MMBs */ | ||
73 | .reserved[CID_RGB0] = 2, | ||
74 | .reserved[CID_RGB1] = 2, | ||
75 | .reserved[CID_RGB2] = 2, | ||
76 | .reserved[CID_RGB3] = 2, | ||
77 | }, | ||
78 | .ctl = { | ||
79 | .count = 5, | ||
80 | .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, | ||
81 | }, | ||
82 | .pipe_vig = { | ||
83 | .count = 4, | ||
84 | .base = { 0x01200, 0x01600, 0x01a00, 0x01e00 }, | ||
85 | }, | ||
86 | .pipe_rgb = { | ||
87 | .count = 4, | ||
88 | .base = { 0x02200, 0x02600, 0x02a00, 0x02e00 }, | ||
89 | }, | ||
90 | .pipe_dma = { | ||
91 | .count = 2, | ||
92 | .base = { 0x03200, 0x03600 }, | ||
93 | }, | ||
94 | .lm = { | ||
95 | .count = 6, | ||
96 | .base = { 0x03a00, 0x03e00, 0x04200, 0x04600, 0x04a00, 0x04e00 }, | ||
97 | .nb_stages = 5, | ||
98 | }, | ||
99 | .dspp = { | ||
100 | .count = 4, | ||
101 | .base = { 0x05200, 0x05600, 0x05a00, 0x05e00 }, | ||
102 | |||
103 | }, | ||
104 | .ad = { | ||
105 | .count = 3, | ||
106 | .base = { 0x13500, 0x13700, 0x13900 }, | ||
107 | }, | ||
108 | .intf = { | ||
109 | .count = 5, | ||
110 | .base = { 0x12500, 0x12700, 0x12900, 0x12b00, 0x12d00 }, | ||
111 | }, | ||
112 | .max_clk = 320000000, | ||
113 | }; | ||
114 | |||
115 | static const struct mdp5_cfg_handler cfg_handlers[] = { | ||
116 | { .revision = 0, .config = { .hw = &msm8x74_config } }, | ||
117 | { .revision = 2, .config = { .hw = &msm8x74_config } }, | ||
118 | { .revision = 3, .config = { .hw = &apq8084_config } }, | ||
119 | }; | ||
120 | |||
121 | |||
122 | static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev); | ||
123 | |||
124 | const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(void *cfg_hnd) | ||
125 | { | ||
126 | struct mdp5_cfg_handler *cfg_handler = cfg_hnd; | ||
127 | |||
128 | return cfg_handler->config.hw; | ||
129 | } | ||
130 | |||
131 | struct mdp5_cfg *mdp5_cfg_get_config(void *cfg_hnd) | ||
132 | { | ||
133 | struct mdp5_cfg_handler *cfg_handler = cfg_hnd; | ||
134 | |||
135 | return &cfg_handler->config; | ||
136 | } | ||
137 | |||
138 | int mdp5_cfg_get_hw_rev(void *cfg_hnd) | ||
139 | { | ||
140 | struct mdp5_cfg_handler *cfg_handler = cfg_hnd; | ||
141 | |||
142 | return cfg_handler->revision; | ||
143 | } | ||
144 | |||
145 | void mdp5_cfg_destroy(void *cfg_hnd) | ||
146 | { | ||
147 | struct mdp5_cfg_handler *cfg_handler = cfg_hnd; | ||
148 | |||
149 | kfree(cfg_handler); | ||
150 | } | ||
151 | |||
152 | void *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, | ||
153 | uint32_t major, uint32_t minor) | ||
154 | { | ||
155 | struct drm_device *dev = mdp5_kms->dev; | ||
156 | struct platform_device *pdev = dev->platformdev; | ||
157 | struct mdp5_cfg_handler *cfg_handler; | ||
158 | struct mdp5_cfg_platform *pconfig; | ||
159 | int i, ret = 0; | ||
160 | |||
161 | cfg_handler = kzalloc(sizeof(*cfg_handler), GFP_KERNEL); | ||
162 | if (unlikely(!cfg_handler)) { | ||
163 | ret = -ENOMEM; | ||
164 | goto fail; | ||
165 | } | ||
166 | |||
167 | if (major != 1) { | ||
168 | dev_err(dev->dev, "unexpected MDP major version: v%d.%d\n", | ||
169 | major, minor); | ||
170 | ret = -ENXIO; | ||
171 | goto fail; | ||
172 | } | ||
173 | |||
174 | /* only after mdp5_cfg global pointer's init can we access the hw */ | ||
175 | for (i = 0; i < ARRAY_SIZE(cfg_handlers); i++) { | ||
176 | if (cfg_handlers[i].revision != minor) | ||
177 | continue; | ||
178 | mdp5_cfg = cfg_handlers[i].config.hw; | ||
179 | |||
180 | break; | ||
181 | } | ||
182 | if (unlikely(!mdp5_cfg)) { | ||
183 | dev_err(dev->dev, "unexpected MDP minor revision: v%d.%d\n", | ||
184 | major, minor); | ||
185 | ret = -ENXIO; | ||
186 | goto fail; | ||
187 | } | ||
188 | |||
189 | cfg_handler->revision = minor; | ||
190 | cfg_handler->config.hw = mdp5_cfg; | ||
191 | |||
192 | pconfig = mdp5_get_config(pdev); | ||
193 | memcpy(&cfg_handler->config.platform, pconfig, sizeof(*pconfig)); | ||
194 | |||
195 | DBG("MDP5: %s hw config selected", mdp5_cfg->name); | ||
196 | |||
197 | return cfg_handler; | ||
198 | |||
199 | fail: | ||
200 | if (cfg_handler) | ||
201 | mdp5_cfg_destroy(cfg_handler); | ||
202 | |||
203 | return NULL; | ||
204 | } | ||
205 | |||
206 | static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev) | ||
207 | { | ||
208 | static struct mdp5_cfg_platform config = {}; | ||
209 | #ifdef CONFIG_OF | ||
210 | /* TODO */ | ||
211 | #endif | ||
212 | config.iommu = iommu_domain_alloc(&platform_bus_type); | ||
213 | |||
214 | return &config; | ||
215 | } | ||
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h new file mode 100644 index 000000000000..00c8271ad928 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 The Linux Foundation. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 and | ||
6 | * only version 2 as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #ifndef __MDP5_CFG_H__ | ||
15 | #define __MDP5_CFG_H__ | ||
16 | |||
17 | #include "msm_drv.h" | ||
18 | |||
19 | /* | ||
20 | * mdp5_cfg | ||
21 | * | ||
22 | * This module configures the dynamic offsets used by mdp5.xml.h | ||
23 | * (initialized in mdp5_cfg.c) | ||
24 | */ | ||
25 | extern const struct mdp5_cfg_hw *mdp5_cfg; | ||
26 | |||
27 | #define MAX_BASES 8 | ||
28 | #define MAX_SMP_BLOCKS 44 | ||
29 | #define MAX_CLIENTS 32 | ||
30 | |||
31 | typedef DECLARE_BITMAP(mdp5_smp_state_t, MAX_SMP_BLOCKS); | ||
32 | |||
33 | #define MDP5_SUB_BLOCK_DEFINITION \ | ||
34 | int count; \ | ||
35 | uint32_t base[MAX_BASES] | ||
36 | |||
37 | struct mdp5_sub_block { | ||
38 | MDP5_SUB_BLOCK_DEFINITION; | ||
39 | }; | ||
40 | |||
41 | struct mdp5_lm_block { | ||
42 | MDP5_SUB_BLOCK_DEFINITION; | ||
43 | uint32_t nb_stages; /* number of stages per blender */ | ||
44 | }; | ||
45 | |||
46 | struct mdp5_smp_block { | ||
47 | int mmb_count; /* number of SMP MMBs */ | ||
48 | int mmb_size; /* MMB: size in bytes */ | ||
49 | mdp5_smp_state_t reserved_state;/* SMP MMBs statically allocated */ | ||
50 | int reserved[MAX_CLIENTS]; /* # of MMBs allocated per client */ | ||
51 | }; | ||
52 | |||
53 | struct mdp5_cfg_hw { | ||
54 | char *name; | ||
55 | |||
56 | struct mdp5_smp_block smp; | ||
57 | struct mdp5_sub_block ctl; | ||
58 | struct mdp5_sub_block pipe_vig; | ||
59 | struct mdp5_sub_block pipe_rgb; | ||
60 | struct mdp5_sub_block pipe_dma; | ||
61 | struct mdp5_lm_block lm; | ||
62 | struct mdp5_sub_block dspp; | ||
63 | struct mdp5_sub_block ad; | ||
64 | struct mdp5_sub_block intf; | ||
65 | |||
66 | uint32_t max_clk; | ||
67 | }; | ||
68 | |||
69 | /* platform config data (ie. from DT, or pdata) */ | ||
70 | struct mdp5_cfg_platform { | ||
71 | struct iommu_domain *iommu; | ||
72 | }; | ||
73 | |||
74 | struct mdp5_cfg { | ||
75 | const struct mdp5_cfg_hw *hw; | ||
76 | struct mdp5_cfg_platform platform; | ||
77 | }; | ||
78 | |||
79 | struct mdp5_kms; | ||
80 | |||
81 | const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(void *cfg_hnd); | ||
82 | struct mdp5_cfg *mdp5_cfg_get_config(void *cfg_hnd); | ||
83 | int mdp5_cfg_get_hw_rev(void *cfg_hnd); | ||
84 | |||
85 | void *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, uint32_t major, uint32_t minor); | ||
86 | void mdp5_cfg_destroy(void *cfg_hnd); | ||
87 | |||
88 | #endif /* __MDP5_CFG_H__ */ | ||
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index f852fa456d93..64de0f9310c3 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2014, The Linux Foundation. All rights reserved. | ||
2 | * Copyright (C) 2013 Red Hat | 3 | * Copyright (C) 2013 Red Hat |
3 | * Author: Rob Clark <robdclark@gmail.com> | 4 | * Author: Rob Clark <robdclark@gmail.com> |
4 | * | 5 | * |
@@ -24,158 +25,10 @@ static const char *iommu_ports[] = { | |||
24 | "mdp_0", | 25 | "mdp_0", |
25 | }; | 26 | }; |
26 | 27 | ||
27 | static struct mdp5_platform_config *mdp5_get_config(struct platform_device *dev); | ||
28 | |||
29 | const struct mdp5_config *mdp5_cfg; | ||
30 | |||
31 | static const struct mdp5_config msm8x74_config = { | ||
32 | .name = "msm8x74", | ||
33 | .smp = { | ||
34 | .mmb_count = 22, | ||
35 | .mmb_size = 4096, | ||
36 | }, | ||
37 | .ctl = { | ||
38 | .count = 5, | ||
39 | .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, | ||
40 | }, | ||
41 | .pipe_vig = { | ||
42 | .count = 3, | ||
43 | .base = { 0x01200, 0x01600, 0x01a00 }, | ||
44 | }, | ||
45 | .pipe_rgb = { | ||
46 | .count = 3, | ||
47 | .base = { 0x01e00, 0x02200, 0x02600 }, | ||
48 | }, | ||
49 | .pipe_dma = { | ||
50 | .count = 2, | ||
51 | .base = { 0x02a00, 0x02e00 }, | ||
52 | }, | ||
53 | .lm = { | ||
54 | .count = 5, | ||
55 | .base = { 0x03200, 0x03600, 0x03a00, 0x03e00, 0x04200 }, | ||
56 | }, | ||
57 | .dspp = { | ||
58 | .count = 3, | ||
59 | .base = { 0x04600, 0x04a00, 0x04e00 }, | ||
60 | }, | ||
61 | .ad = { | ||
62 | .count = 2, | ||
63 | .base = { 0x13100, 0x13300 }, /* NOTE: no ad in v1.0 */ | ||
64 | }, | ||
65 | .intf = { | ||
66 | .count = 4, | ||
67 | .base = { 0x12500, 0x12700, 0x12900, 0x12b00 }, | ||
68 | }, | ||
69 | .max_clk = 200000000, | ||
70 | }; | ||
71 | |||
72 | static const struct mdp5_config apq8084_config = { | ||
73 | .name = "apq8084", | ||
74 | .smp = { | ||
75 | .mmb_count = 44, | ||
76 | .mmb_size = 8192, | ||
77 | .reserved_state[0] = GENMASK(7, 0), /* first 8 MMBs */ | ||
78 | .reserved[CID_RGB0] = 2, | ||
79 | .reserved[CID_RGB1] = 2, | ||
80 | .reserved[CID_RGB2] = 2, | ||
81 | .reserved[CID_RGB3] = 2, | ||
82 | }, | ||
83 | .ctl = { | ||
84 | .count = 5, | ||
85 | .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, | ||
86 | }, | ||
87 | .pipe_vig = { | ||
88 | .count = 4, | ||
89 | .base = { 0x01200, 0x01600, 0x01a00, 0x01e00 }, | ||
90 | }, | ||
91 | .pipe_rgb = { | ||
92 | .count = 4, | ||
93 | .base = { 0x02200, 0x02600, 0x02a00, 0x02e00 }, | ||
94 | }, | ||
95 | .pipe_dma = { | ||
96 | .count = 2, | ||
97 | .base = { 0x03200, 0x03600 }, | ||
98 | }, | ||
99 | .lm = { | ||
100 | .count = 6, | ||
101 | .base = { 0x03a00, 0x03e00, 0x04200, 0x04600, 0x04a00, 0x04e00 }, | ||
102 | }, | ||
103 | .dspp = { | ||
104 | .count = 4, | ||
105 | .base = { 0x05200, 0x05600, 0x05a00, 0x05e00 }, | ||
106 | |||
107 | }, | ||
108 | .ad = { | ||
109 | .count = 3, | ||
110 | .base = { 0x13500, 0x13700, 0x13900 }, | ||
111 | }, | ||
112 | .intf = { | ||
113 | .count = 5, | ||
114 | .base = { 0x12500, 0x12700, 0x12900, 0x12b00, 0x12d00 }, | ||
115 | }, | ||
116 | .max_clk = 320000000, | ||
117 | }; | ||
118 | |||
119 | struct mdp5_config_entry { | ||
120 | int revision; | ||
121 | const struct mdp5_config *config; | ||
122 | }; | ||
123 | |||
124 | static const struct mdp5_config_entry mdp5_configs[] = { | ||
125 | { .revision = 0, .config = &msm8x74_config }, | ||
126 | { .revision = 2, .config = &msm8x74_config }, | ||
127 | { .revision = 3, .config = &apq8084_config }, | ||
128 | }; | ||
129 | |||
130 | static int mdp5_select_hw_cfg(struct msm_kms *kms) | ||
131 | { | ||
132 | struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); | ||
133 | struct drm_device *dev = mdp5_kms->dev; | ||
134 | uint32_t version, major, minor; | ||
135 | int i, ret = 0; | ||
136 | |||
137 | mdp5_enable(mdp5_kms); | ||
138 | version = mdp5_read(mdp5_kms, REG_MDP5_MDP_VERSION); | ||
139 | mdp5_disable(mdp5_kms); | ||
140 | |||
141 | major = FIELD(version, MDP5_MDP_VERSION_MAJOR); | ||
142 | minor = FIELD(version, MDP5_MDP_VERSION_MINOR); | ||
143 | |||
144 | DBG("found MDP5 version v%d.%d", major, minor); | ||
145 | |||
146 | if (major != 1) { | ||
147 | dev_err(dev->dev, "unexpected MDP major version: v%d.%d\n", | ||
148 | major, minor); | ||
149 | ret = -ENXIO; | ||
150 | goto out; | ||
151 | } | ||
152 | |||
153 | mdp5_kms->rev = minor; | ||
154 | |||
155 | /* only after mdp5_cfg global pointer's init can we access the hw */ | ||
156 | for (i = 0; i < ARRAY_SIZE(mdp5_configs); i++) { | ||
157 | if (mdp5_configs[i].revision != minor) | ||
158 | continue; | ||
159 | mdp5_kms->hw_cfg = mdp5_cfg = mdp5_configs[i].config; | ||
160 | break; | ||
161 | } | ||
162 | if (unlikely(!mdp5_kms->hw_cfg)) { | ||
163 | dev_err(dev->dev, "unexpected MDP minor revision: v%d.%d\n", | ||
164 | major, minor); | ||
165 | ret = -ENXIO; | ||
166 | goto out; | ||
167 | } | ||
168 | |||
169 | DBG("MDP5: %s config selected", mdp5_kms->hw_cfg->name); | ||
170 | |||
171 | return 0; | ||
172 | out: | ||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | static int mdp5_hw_init(struct msm_kms *kms) | 28 | static int mdp5_hw_init(struct msm_kms *kms) |
177 | { | 29 | { |
178 | struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); | 30 | struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); |
31 | const struct mdp5_cfg_hw *hw_cfg; | ||
179 | struct drm_device *dev = mdp5_kms->dev; | 32 | struct drm_device *dev = mdp5_kms->dev; |
180 | int i; | 33 | int i; |
181 | 34 | ||
@@ -207,7 +60,9 @@ static int mdp5_hw_init(struct msm_kms *kms) | |||
207 | 60 | ||
208 | mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, 0); | 61 | mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, 0); |
209 | 62 | ||
210 | for (i = 0; i < mdp5_kms->hw_cfg->ctl.count; i++) | 63 | hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg_priv); |
64 | |||
65 | for (i = 0; i < hw_cfg->ctl.count; i++) | ||
211 | mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(i), 0); | 66 | mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(i), 0); |
212 | 67 | ||
213 | pm_runtime_put_sync(dev->dev); | 68 | pm_runtime_put_sync(dev->dev); |
@@ -236,6 +91,7 @@ static void mdp5_destroy(struct msm_kms *kms) | |||
236 | struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); | 91 | struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); |
237 | struct msm_mmu *mmu = mdp5_kms->mmu; | 92 | struct msm_mmu *mmu = mdp5_kms->mmu; |
238 | void *smp = mdp5_kms->smp_priv; | 93 | void *smp = mdp5_kms->smp_priv; |
94 | void *cfg = mdp5_kms->cfg_priv; | ||
239 | 95 | ||
240 | mdp5_irq_domain_fini(mdp5_kms); | 96 | mdp5_irq_domain_fini(mdp5_kms); |
241 | 97 | ||
@@ -246,6 +102,8 @@ static void mdp5_destroy(struct msm_kms *kms) | |||
246 | 102 | ||
247 | if (smp) | 103 | if (smp) |
248 | mdp5_smp_destroy(smp); | 104 | mdp5_smp_destroy(smp); |
105 | if (cfg) | ||
106 | mdp5_cfg_destroy(cfg); | ||
249 | 107 | ||
250 | kfree(mdp5_kms); | 108 | kfree(mdp5_kms); |
251 | } | 109 | } |
@@ -299,8 +157,11 @@ static int modeset_init(struct mdp5_kms *mdp5_kms) | |||
299 | struct drm_device *dev = mdp5_kms->dev; | 157 | struct drm_device *dev = mdp5_kms->dev; |
300 | struct msm_drm_private *priv = dev->dev_private; | 158 | struct msm_drm_private *priv = dev->dev_private; |
301 | struct drm_encoder *encoder; | 159 | struct drm_encoder *encoder; |
160 | const struct mdp5_cfg_hw *hw_cfg; | ||
302 | int i, ret; | 161 | int i, ret; |
303 | 162 | ||
163 | hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg_priv); | ||
164 | |||
304 | /* register our interrupt-controller for hdmi/eDP/dsi/etc | 165 | /* register our interrupt-controller for hdmi/eDP/dsi/etc |
305 | * to use for irqs routed through mdp: | 166 | * to use for irqs routed through mdp: |
306 | */ | 167 | */ |
@@ -309,7 +170,7 @@ static int modeset_init(struct mdp5_kms *mdp5_kms) | |||
309 | goto fail; | 170 | goto fail; |
310 | 171 | ||
311 | /* construct CRTCs: */ | 172 | /* construct CRTCs: */ |
312 | for (i = 0; i < mdp5_kms->hw_cfg->pipe_rgb.count; i++) { | 173 | for (i = 0; i < hw_cfg->pipe_rgb.count; i++) { |
313 | struct drm_plane *plane; | 174 | struct drm_plane *plane; |
314 | struct drm_crtc *crtc; | 175 | struct drm_crtc *crtc; |
315 | 176 | ||
@@ -367,6 +228,21 @@ fail: | |||
367 | return ret; | 228 | return ret; |
368 | } | 229 | } |
369 | 230 | ||
231 | static void read_hw_revision(struct mdp5_kms *mdp5_kms, | ||
232 | uint32_t *major, uint32_t *minor) | ||
233 | { | ||
234 | uint32_t version; | ||
235 | |||
236 | mdp5_enable(mdp5_kms); | ||
237 | version = mdp5_read(mdp5_kms, REG_MDP5_MDP_VERSION); | ||
238 | mdp5_disable(mdp5_kms); | ||
239 | |||
240 | *major = FIELD(version, MDP5_MDP_VERSION_MAJOR); | ||
241 | *minor = FIELD(version, MDP5_MDP_VERSION_MINOR); | ||
242 | |||
243 | DBG("MDP5 version v%d.%d", *major, *minor); | ||
244 | } | ||
245 | |||
370 | static int get_clk(struct platform_device *pdev, struct clk **clkp, | 246 | static int get_clk(struct platform_device *pdev, struct clk **clkp, |
371 | const char *name) | 247 | const char *name) |
372 | { | 248 | { |
@@ -383,10 +259,11 @@ static int get_clk(struct platform_device *pdev, struct clk **clkp, | |||
383 | struct msm_kms *mdp5_kms_init(struct drm_device *dev) | 259 | struct msm_kms *mdp5_kms_init(struct drm_device *dev) |
384 | { | 260 | { |
385 | struct platform_device *pdev = dev->platformdev; | 261 | struct platform_device *pdev = dev->platformdev; |
386 | struct mdp5_platform_config *config = mdp5_get_config(pdev); | 262 | struct mdp5_cfg *config; |
387 | struct mdp5_kms *mdp5_kms; | 263 | struct mdp5_kms *mdp5_kms; |
388 | struct msm_kms *kms = NULL; | 264 | struct msm_kms *kms = NULL; |
389 | struct msm_mmu *mmu; | 265 | struct msm_mmu *mmu; |
266 | uint32_t major, minor; | ||
390 | void *priv; | 267 | void *priv; |
391 | int i, ret; | 268 | int i, ret; |
392 | 269 | ||
@@ -446,14 +323,19 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) | |||
446 | if (ret) | 323 | if (ret) |
447 | goto fail; | 324 | goto fail; |
448 | 325 | ||
449 | ret = mdp5_select_hw_cfg(kms); | 326 | read_hw_revision(mdp5_kms, &major, &minor); |
450 | if (ret) | 327 | priv = mdp5_cfg_init(mdp5_kms, major, minor); |
328 | if (IS_ERR(priv)) { | ||
329 | ret = PTR_ERR(priv); | ||
451 | goto fail; | 330 | goto fail; |
331 | } | ||
332 | mdp5_kms->cfg_priv = priv; | ||
333 | config = mdp5_cfg_get_config(mdp5_kms->cfg_priv); | ||
452 | 334 | ||
453 | /* TODO: compute core clock rate at runtime */ | 335 | /* TODO: compute core clock rate at runtime */ |
454 | clk_set_rate(mdp5_kms->src_clk, mdp5_kms->hw_cfg->max_clk); | 336 | clk_set_rate(mdp5_kms->src_clk, config->hw->max_clk); |
455 | 337 | ||
456 | priv = mdp5_smp_init(mdp5_kms->dev, &mdp5_kms->hw_cfg->smp); | 338 | priv = mdp5_smp_init(mdp5_kms->dev, &config->hw->smp); |
457 | if (IS_ERR(priv)) { | 339 | if (IS_ERR(priv)) { |
458 | ret = PTR_ERR(priv); | 340 | ret = PTR_ERR(priv); |
459 | goto fail; | 341 | goto fail; |
@@ -465,13 +347,13 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) | |||
465 | * we don't disable): | 347 | * we don't disable): |
466 | */ | 348 | */ |
467 | mdp5_enable(mdp5_kms); | 349 | mdp5_enable(mdp5_kms); |
468 | for (i = 0; i < mdp5_kms->hw_cfg->intf.count; i++) | 350 | for (i = 0; i < config->hw->intf.count; i++) |
469 | mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0); | 351 | mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0); |
470 | mdp5_disable(mdp5_kms); | 352 | mdp5_disable(mdp5_kms); |
471 | mdelay(16); | 353 | mdelay(16); |
472 | 354 | ||
473 | if (config->iommu) { | 355 | if (config->platform.iommu) { |
474 | mmu = msm_iommu_new(&pdev->dev, config->iommu); | 356 | mmu = msm_iommu_new(&pdev->dev, config->platform.iommu); |
475 | if (IS_ERR(mmu)) { | 357 | if (IS_ERR(mmu)) { |
476 | ret = PTR_ERR(mmu); | 358 | ret = PTR_ERR(mmu); |
477 | dev_err(dev->dev, "failed to init iommu: %d\n", ret); | 359 | dev_err(dev->dev, "failed to init iommu: %d\n", ret); |
@@ -512,14 +394,3 @@ fail: | |||
512 | mdp5_destroy(kms); | 394 | mdp5_destroy(kms); |
513 | return ERR_PTR(ret); | 395 | return ERR_PTR(ret); |
514 | } | 396 | } |
515 | |||
516 | static struct mdp5_platform_config *mdp5_get_config(struct platform_device *dev) | ||
517 | { | ||
518 | static struct mdp5_platform_config config = {}; | ||
519 | #ifdef CONFIG_OF | ||
520 | /* TODO */ | ||
521 | #endif | ||
522 | config.iommu = iommu_domain_alloc(&platform_bus_type); | ||
523 | |||
524 | return &config; | ||
525 | } | ||
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index 3f7aa49dd944..daca8da64666 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h | |||
@@ -21,36 +21,7 @@ | |||
21 | #include "msm_drv.h" | 21 | #include "msm_drv.h" |
22 | #include "msm_kms.h" | 22 | #include "msm_kms.h" |
23 | #include "mdp/mdp_kms.h" | 23 | #include "mdp/mdp_kms.h" |
24 | /* dynamic offsets used by mdp5.xml.h (initialized in mdp5_kms.c) */ | 24 | #include "mdp5_cfg.h" /* must be included before mdp5.xml.h */ |
25 | #define MDP5_MAX_BASES 8 | ||
26 | #define MAX_SMP_BLOCKS 44 | ||
27 | #define MAX_CLIENTS 32 | ||
28 | typedef DECLARE_BITMAP(mdp5_smp_state_t, MAX_SMP_BLOCKS); | ||
29 | struct mdp5_sub_block { | ||
30 | int count; | ||
31 | uint32_t base[MDP5_MAX_BASES]; | ||
32 | }; | ||
33 | struct mdp5_smp_block { | ||
34 | int mmb_count; /* number of SMP MMBs */ | ||
35 | int mmb_size; /* MMB: size in bytes */ | ||
36 | mdp5_smp_state_t reserved_state;/* SMP MMBs statically allocated */ | ||
37 | int reserved[MAX_CLIENTS]; /* # of MMBs reserved per client */ | ||
38 | }; | ||
39 | struct mdp5_config { | ||
40 | char *name; | ||
41 | struct mdp5_smp_block smp; | ||
42 | struct mdp5_sub_block ctl; | ||
43 | struct mdp5_sub_block pipe_vig; | ||
44 | struct mdp5_sub_block pipe_rgb; | ||
45 | struct mdp5_sub_block pipe_dma; | ||
46 | struct mdp5_sub_block lm; | ||
47 | struct mdp5_sub_block dspp; | ||
48 | struct mdp5_sub_block ad; | ||
49 | struct mdp5_sub_block intf; | ||
50 | |||
51 | uint32_t max_clk; | ||
52 | }; | ||
53 | extern const struct mdp5_config *mdp5_cfg; | ||
54 | #include "mdp5.xml.h" | 25 | #include "mdp5.xml.h" |
55 | #include "mdp5_smp.h" | 26 | #include "mdp5_smp.h" |
56 | 27 | ||
@@ -59,8 +30,7 @@ struct mdp5_kms { | |||
59 | 30 | ||
60 | struct drm_device *dev; | 31 | struct drm_device *dev; |
61 | 32 | ||
62 | int rev; | 33 | void *cfg_priv; |
63 | const struct mdp5_config *hw_cfg; | ||
64 | 34 | ||
65 | /* mapper-id used to request GEM buffer mapped for scanout: */ | 35 | /* mapper-id used to request GEM buffer mapped for scanout: */ |
66 | int id; | 36 | int id; |
@@ -89,11 +59,6 @@ struct mdp5_kms { | |||
89 | }; | 59 | }; |
90 | #define to_mdp5_kms(x) container_of(x, struct mdp5_kms, base) | 60 | #define to_mdp5_kms(x) container_of(x, struct mdp5_kms, base) |
91 | 61 | ||
92 | /* platform config data (ie. from DT, or pdata) */ | ||
93 | struct mdp5_platform_config { | ||
94 | struct iommu_domain *iommu; | ||
95 | }; | ||
96 | |||
97 | static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data) | 62 | static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data) |
98 | { | 63 | { |
99 | msm_writel(data, mdp5_kms->mmio + reg); | 64 | msm_writel(data, mdp5_kms->mmio + reg); |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c index e61e1cfed853..04996cae4585 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c | |||
@@ -108,11 +108,15 @@ static int smp_request_block(struct mdp5_smp *smp, | |||
108 | enum mdp5_client_id cid, int nblks) | 108 | enum mdp5_client_id cid, int nblks) |
109 | { | 109 | { |
110 | struct mdp5_kms *mdp5_kms = get_kms(smp); | 110 | struct mdp5_kms *mdp5_kms = get_kms(smp); |
111 | const struct mdp5_cfg_hw *hw_cfg; | ||
111 | struct mdp5_client_smp_state *ps = &smp->client_state[cid]; | 112 | struct mdp5_client_smp_state *ps = &smp->client_state[cid]; |
112 | int i, ret, avail, cur_nblks, cnt = smp->blk_cnt; | 113 | int i, ret, avail, cur_nblks, cnt = smp->blk_cnt; |
113 | int reserved = mdp5_kms->hw_cfg->smp.reserved[cid]; | 114 | int reserved; |
114 | unsigned long flags; | 115 | unsigned long flags; |
115 | 116 | ||
117 | hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg_priv); | ||
118 | reserved = hw_cfg->smp.reserved[cid]; | ||
119 | |||
116 | spin_lock_irqsave(&smp->state_lock, flags); | 120 | spin_lock_irqsave(&smp->state_lock, flags); |
117 | 121 | ||
118 | nblks -= reserved; | 122 | nblks -= reserved; |
@@ -175,6 +179,7 @@ int mdp5_smp_request(void *handler, enum mdp5_pipe pipe, u32 fmt, u32 width) | |||
175 | struct mdp5_smp *smp = handler; | 179 | struct mdp5_smp *smp = handler; |
176 | struct mdp5_kms *mdp5_kms = get_kms(smp); | 180 | struct mdp5_kms *mdp5_kms = get_kms(smp); |
177 | struct drm_device *dev = mdp5_kms->dev; | 181 | struct drm_device *dev = mdp5_kms->dev; |
182 | int rev = mdp5_cfg_get_hw_rev(mdp5_kms->cfg_priv); | ||
178 | int i, hsub, nplanes, nlines, nblks, ret; | 183 | int i, hsub, nplanes, nlines, nblks, ret; |
179 | 184 | ||
180 | nplanes = drm_format_num_planes(fmt); | 185 | nplanes = drm_format_num_planes(fmt); |
@@ -192,7 +197,7 @@ int mdp5_smp_request(void *handler, enum mdp5_pipe pipe, u32 fmt, u32 width) | |||
192 | n = DIV_ROUND_UP(fetch_stride * nlines, smp->blk_size); | 197 | n = DIV_ROUND_UP(fetch_stride * nlines, smp->blk_size); |
193 | 198 | ||
194 | /* for hw rev v1.00 */ | 199 | /* for hw rev v1.00 */ |
195 | if (mdp5_kms->rev == 0) | 200 | if (rev == 0) |
196 | n = roundup_pow_of_two(n); | 201 | n = roundup_pow_of_two(n); |
197 | 202 | ||
198 | DBG("%s[%d]: request %d SMP blocks", pipe2name(pipe), i, n); | 203 | DBG("%s[%d]: request %d SMP blocks", pipe2name(pipe), i, n); |