|
26 | 26 | #define DISP_GAMMA_SIZE_VSIZE GENMASK(12, 0) |
27 | 27 | #define DISP_GAMMA_BANK 0x0100 |
28 | 28 | #define DISP_GAMMA_BANK_BANK GENMASK(1, 0) |
| 29 | +#define DISP_GAMMA_BANK_DATA_MODE BIT(2) |
29 | 30 | #define DISP_GAMMA_LUT 0x0700 |
| 31 | +#define DISP_GAMMA_LUT1 0x0b00 |
30 | 32 |
|
| 33 | +/* For 10 bit LUT layout, R/G/B are in the same register */ |
31 | 34 | #define DISP_GAMMA_LUT_10BIT_R GENMASK(29, 20) |
32 | 35 | #define DISP_GAMMA_LUT_10BIT_G GENMASK(19, 10) |
33 | 36 | #define DISP_GAMMA_LUT_10BIT_B GENMASK(9, 0) |
34 | 37 |
|
| 38 | +/* For 12 bit LUT layout, R/G are in LUT, B is in LUT1 */ |
| 39 | +#define DISP_GAMMA_LUT_12BIT_R GENMASK(11, 0) |
| 40 | +#define DISP_GAMMA_LUT_12BIT_G GENMASK(23, 12) |
| 41 | +#define DISP_GAMMA_LUT_12BIT_B GENMASK(11, 0) |
| 42 | + |
35 | 43 | struct mtk_disp_gamma_data { |
36 | 44 | bool has_dither; |
37 | 45 | bool lut_diff; |
38 | 46 | u16 lut_bank_size; |
39 | 47 | u16 lut_size; |
| 48 | + u8 lut_bits; |
40 | 49 | }; |
41 | 50 |
|
42 | 51 | /* |
@@ -72,58 +81,92 @@ unsigned int mtk_gamma_get_lut_size(struct device *dev) |
72 | 81 | return 0; |
73 | 82 | } |
74 | 83 |
|
| 84 | +/* |
| 85 | + * SoCs supporting 12-bits LUTs are using a new register layout that does |
| 86 | + * always support (by HW) both 12-bits and 10-bits LUT but, on those, we |
| 87 | + * ignore the support for 10-bits in this driver and always use 12-bits. |
| 88 | + * |
| 89 | + * Summarizing: |
| 90 | + * - SoC HW support 9/10-bits LUT only |
| 91 | + * - Old register layout |
| 92 | + * - 10-bits LUT supported |
| 93 | + * - 9-bits LUT not supported |
| 94 | + * - SoC HW support both 10/12bits LUT |
| 95 | + * - New register layout |
| 96 | + * - 12-bits LUT supported |
| 97 | + * - 10-its LUT not supported |
| 98 | + */ |
75 | 99 | void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state) |
76 | 100 | { |
77 | 101 | struct mtk_disp_gamma *gamma = dev_get_drvdata(dev); |
78 | | - unsigned int i; |
79 | | - struct drm_color_lut *lut; |
80 | | - void __iomem *lut_base; |
81 | | - u32 cfg_val, lbank_val, word; |
| 102 | + void __iomem *lut0_base = gamma->regs + DISP_GAMMA_LUT; |
| 103 | + void __iomem *lut1_base = gamma->regs + DISP_GAMMA_LUT1; |
| 104 | + u32 cfg_val, data_mode, lbank_val, word[2]; |
| 105 | + u8 lut_bits = gamma->data->lut_bits; |
82 | 106 | int cur_bank, num_lut_banks; |
| 107 | + struct drm_color_lut *lut; |
| 108 | + unsigned int i; |
83 | 109 |
|
84 | 110 | /* If there's no gamma lut there's nothing to do here. */ |
85 | 111 | if (!state->gamma_lut) |
86 | 112 | return; |
87 | 113 |
|
88 | 114 | num_lut_banks = gamma->data->lut_size / gamma->data->lut_bank_size; |
89 | | - lut_base = gamma->regs + DISP_GAMMA_LUT; |
90 | 115 | lut = (struct drm_color_lut *)state->gamma_lut->data; |
91 | 116 |
|
| 117 | + /* Switch to 12 bits data mode if supported */ |
| 118 | + data_mode = FIELD_PREP(DISP_GAMMA_BANK_DATA_MODE, !!(lut_bits == 12)); |
| 119 | + |
92 | 120 | for (cur_bank = 0; cur_bank < num_lut_banks; cur_bank++) { |
93 | 121 |
|
94 | 122 | /* Switch gamma bank and set data mode before writing LUT */ |
95 | 123 | if (num_lut_banks > 1) { |
96 | 124 | lbank_val = FIELD_PREP(DISP_GAMMA_BANK_BANK, cur_bank); |
| 125 | + lbank_val |= data_mode; |
97 | 126 | writel(lbank_val, gamma->regs + DISP_GAMMA_BANK); |
98 | 127 | } |
99 | 128 |
|
100 | 129 | for (i = 0; i < gamma->data->lut_bank_size; i++) { |
101 | 130 | int n = cur_bank * gamma->data->lut_bank_size + i; |
102 | 131 | struct drm_color_lut diff, hwlut; |
103 | 132 |
|
104 | | - hwlut.red = drm_color_lut_extract(lut[n].red, 10); |
105 | | - hwlut.green = drm_color_lut_extract(lut[n].green, 10); |
106 | | - hwlut.blue = drm_color_lut_extract(lut[n].blue, 10); |
| 133 | + hwlut.red = drm_color_lut_extract(lut[n].red, lut_bits); |
| 134 | + hwlut.green = drm_color_lut_extract(lut[n].green, lut_bits); |
| 135 | + hwlut.blue = drm_color_lut_extract(lut[n].blue, lut_bits); |
107 | 136 |
|
108 | 137 | if (!gamma->data->lut_diff || (i % 2 == 0)) { |
109 | | - word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red); |
110 | | - word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, hwlut.green); |
111 | | - word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue); |
| 138 | + if (lut_bits == 12) { |
| 139 | + word[0] = FIELD_PREP(DISP_GAMMA_LUT_12BIT_R, hwlut.red); |
| 140 | + word[0] |= FIELD_PREP(DISP_GAMMA_LUT_12BIT_G, hwlut.green); |
| 141 | + word[1] = FIELD_PREP(DISP_GAMMA_LUT_12BIT_B, hwlut.blue); |
| 142 | + } else { |
| 143 | + word[0] = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red); |
| 144 | + word[0] |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, hwlut.green); |
| 145 | + word[0] |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue); |
| 146 | + } |
112 | 147 | } else { |
113 | 148 | diff.red = lut[n].red - lut[n - 1].red; |
114 | | - diff.red = drm_color_lut_extract(diff.red, 10); |
| 149 | + diff.red = drm_color_lut_extract(diff.red, lut_bits); |
115 | 150 |
|
116 | 151 | diff.green = lut[n].green - lut[n - 1].green; |
117 | | - diff.green = drm_color_lut_extract(diff.green, 10); |
| 152 | + diff.green = drm_color_lut_extract(diff.green, lut_bits); |
118 | 153 |
|
119 | 154 | diff.blue = lut[n].blue - lut[n - 1].blue; |
120 | | - diff.blue = drm_color_lut_extract(diff.blue, 10); |
121 | | - |
122 | | - word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, diff.red); |
123 | | - word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, diff.green); |
124 | | - word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, diff.blue); |
| 155 | + diff.blue = drm_color_lut_extract(diff.blue, lut_bits); |
| 156 | + |
| 157 | + if (lut_bits == 12) { |
| 158 | + word[0] = FIELD_PREP(DISP_GAMMA_LUT_12BIT_R, diff.red); |
| 159 | + word[0] |= FIELD_PREP(DISP_GAMMA_LUT_12BIT_G, diff.green); |
| 160 | + word[1] = FIELD_PREP(DISP_GAMMA_LUT_12BIT_B, diff.blue); |
| 161 | + } else { |
| 162 | + word[0] = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, diff.red); |
| 163 | + word[0] |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, diff.green); |
| 164 | + word[0] |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, diff.blue); |
| 165 | + } |
125 | 166 | } |
126 | | - writel(word, lut_base + i * 4); |
| 167 | + writel(word[0], lut0_base + i * 4); |
| 168 | + if (lut_bits == 12) |
| 169 | + writel(word[1], lut1_base + i * 4); |
127 | 170 | } |
128 | 171 | } |
129 | 172 |
|
@@ -229,11 +272,13 @@ static void mtk_disp_gamma_remove(struct platform_device *pdev) |
229 | 272 | static const struct mtk_disp_gamma_data mt8173_gamma_driver_data = { |
230 | 273 | .has_dither = true, |
231 | 274 | .lut_bank_size = 512, |
| 275 | + .lut_bits = 10, |
232 | 276 | .lut_size = 512, |
233 | 277 | }; |
234 | 278 |
|
235 | 279 | static const struct mtk_disp_gamma_data mt8183_gamma_driver_data = { |
236 | 280 | .lut_bank_size = 512, |
| 281 | + .lut_bits = 10, |
237 | 282 | .lut_diff = true, |
238 | 283 | .lut_size = 512, |
239 | 284 | }; |
|
0 commit comments