|
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