]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/gpu/drm/nouveau/nouveau_backlight.c
drm/nouveau: port remainder of drm code, and rip out compat layer
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / nouveau / nouveau_backlight.c
CommitLineData
6ee73861
BS
1/*
2 * Copyright (C) 2009 Red Hat <mjg@redhat.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 */
25
26/*
27 * Authors:
28 * Matthew Garrett <mjg@redhat.com>
29 *
30 * Register locations derived from NVClock by Roderick Colenbrander
31 */
32
33#include <linux/backlight.h>
5bead799 34#include <linux/acpi.h>
6ee73861 35
51a3d342 36#include "nouveau_drm.h"
6ee73861 37#include "nouveau_reg.h"
10b461e4 38#include "nouveau_encoder.h"
6ee73861 39
73076481
BS
40static int
41nv40_get_intensity(struct backlight_device *bd)
6ee73861 42{
51a3d342
BS
43 struct nouveau_drm *drm = bl_get_data(bd);
44 struct nouveau_device *device = nv_device(drm->device);
45 int val = (nv_rd32(device, NV40_PMC_BACKLIGHT) &
46 NV40_PMC_BACKLIGHT_MASK) >> 16;
6ee73861
BS
47
48 return val;
49}
50
73076481
BS
51static int
52nv40_set_intensity(struct backlight_device *bd)
6ee73861 53{
51a3d342
BS
54 struct nouveau_drm *drm = bl_get_data(bd);
55 struct nouveau_device *device = nv_device(drm->device);
6ee73861 56 int val = bd->props.brightness;
51a3d342 57 int reg = nv_rd32(device, NV40_PMC_BACKLIGHT);
6ee73861 58
51a3d342 59 nv_wr32(device, NV40_PMC_BACKLIGHT,
6ee73861
BS
60 (val << 16) | (reg & ~NV40_PMC_BACKLIGHT_MASK));
61
62 return 0;
63}
64
acc2472e 65static const struct backlight_ops nv40_bl_ops = {
6ee73861
BS
66 .options = BL_CORE_SUSPENDRESUME,
67 .get_brightness = nv40_get_intensity,
68 .update_status = nv40_set_intensity,
69};
70
73076481
BS
71static int
72nv40_backlight_init(struct drm_connector *connector)
6ee73861 73{
77145f1c 74 struct nouveau_drm *drm = nouveau_drm(connector->dev);
51a3d342 75 struct nouveau_device *device = nv_device(drm->device);
7eae3efa 76 struct backlight_properties props;
6ee73861
BS
77 struct backlight_device *bd;
78
51a3d342 79 if (!(nv_rd32(device, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK))
6ee73861
BS
80 return 0;
81
a19a6ee6 82 memset(&props, 0, sizeof(struct backlight_properties));
bb7ca747 83 props.type = BACKLIGHT_RAW;
a19a6ee6 84 props.max_brightness = 31;
51a3d342 85 bd = backlight_device_register("nv_backlight", &connector->kdev, drm,
a19a6ee6 86 &nv40_bl_ops, &props);
51a3d342 87 drm->backlight = bd;
6ee73861
BS
88 bd->props.brightness = nv40_get_intensity(bd);
89 backlight_update_status(bd);
90
91 return 0;
92}
93
73076481
BS
94static int
95nv50_get_intensity(struct backlight_device *bd)
96{
10b461e4 97 struct nouveau_encoder *nv_encoder = bl_get_data(bd);
77145f1c 98 struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev);
51a3d342 99 struct nouveau_device *device = nv_device(drm->device);
10b461e4 100 int or = nv_encoder->or;
09461459
BS
101 u32 div = 1025;
102 u32 val;
73076481 103
51a3d342 104 val = nv_rd32(device, NV50_PDISP_SOR_PWM_CTL(or));
5024c54b 105 val &= NV50_PDISP_SOR_PWM_CTL_VAL;
09461459 106 return ((val * 100) + (div / 2)) / div;
73076481
BS
107}
108
109static int
110nv50_set_intensity(struct backlight_device *bd)
111{
10b461e4 112 struct nouveau_encoder *nv_encoder = bl_get_data(bd);
77145f1c 113 struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev);
51a3d342 114 struct nouveau_device *device = nv_device(drm->device);
10b461e4 115 int or = nv_encoder->or;
09461459
BS
116 u32 div = 1025;
117 u32 val = (bd->props.brightness * div) / 100;
73076481 118
51a3d342
BS
119 nv_wr32(device, NV50_PDISP_SOR_PWM_CTL(or),
120 NV50_PDISP_SOR_PWM_CTL_NEW | val);
73076481
BS
121 return 0;
122}
123
124static const struct backlight_ops nv50_bl_ops = {
125 .options = BL_CORE_SUSPENDRESUME,
126 .get_brightness = nv50_get_intensity,
127 .update_status = nv50_set_intensity,
128};
129
5024c54b
BS
130static int
131nva3_get_intensity(struct backlight_device *bd)
132{
133 struct nouveau_encoder *nv_encoder = bl_get_data(bd);
77145f1c 134 struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev);
51a3d342 135 struct nouveau_device *device = nv_device(drm->device);
5024c54b
BS
136 int or = nv_encoder->or;
137 u32 div, val;
138
51a3d342
BS
139 div = nv_rd32(device, NV50_PDISP_SOR_PWM_DIV(or));
140 val = nv_rd32(device, NV50_PDISP_SOR_PWM_CTL(or));
5024c54b
BS
141 val &= NVA3_PDISP_SOR_PWM_CTL_VAL;
142 if (div && div >= val)
143 return ((val * 100) + (div / 2)) / div;
144
145 return 100;
146}
147
148static int
149nva3_set_intensity(struct backlight_device *bd)
150{
151 struct nouveau_encoder *nv_encoder = bl_get_data(bd);
77145f1c 152 struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev);
51a3d342 153 struct nouveau_device *device = nv_device(drm->device);
5024c54b
BS
154 int or = nv_encoder->or;
155 u32 div, val;
156
51a3d342 157 div = nv_rd32(device, NV50_PDISP_SOR_PWM_DIV(or));
5024c54b
BS
158 val = (bd->props.brightness * div) / 100;
159 if (div) {
51a3d342
BS
160 nv_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), val |
161 NV50_PDISP_SOR_PWM_CTL_NEW |
162 NVA3_PDISP_SOR_PWM_CTL_UNK);
5024c54b
BS
163 return 0;
164 }
165
166 return -EINVAL;
167}
168
169static const struct backlight_ops nva3_bl_ops = {
170 .options = BL_CORE_SUSPENDRESUME,
171 .get_brightness = nva3_get_intensity,
172 .update_status = nva3_set_intensity,
173};
174
73076481
BS
175static int
176nv50_backlight_init(struct drm_connector *connector)
6ee73861 177{
77145f1c 178 struct nouveau_drm *drm = nouveau_drm(connector->dev);
51a3d342 179 struct nouveau_device *device = nv_device(drm->device);
10b461e4 180 struct nouveau_encoder *nv_encoder;
7eae3efa 181 struct backlight_properties props;
6ee73861 182 struct backlight_device *bd;
5024c54b 183 const struct backlight_ops *ops;
10b461e4 184
cb75d97e 185 nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS);
10b461e4 186 if (!nv_encoder) {
cb75d97e 187 nv_encoder = find_encoder(connector, DCB_OUTPUT_DP);
10b461e4
BS
188 if (!nv_encoder)
189 return -ENODEV;
190 }
191
51a3d342 192 if (!nv_rd32(device, NV50_PDISP_SOR_PWM_CTL(nv_encoder->or)))
6ee73861
BS
193 return 0;
194
51a3d342
BS
195 if (device->chipset <= 0xa0 ||
196 device->chipset == 0xaa ||
197 device->chipset == 0xac)
5024c54b
BS
198 ops = &nv50_bl_ops;
199 else
200 ops = &nva3_bl_ops;
201
a19a6ee6 202 memset(&props, 0, sizeof(struct backlight_properties));
bb7ca747 203 props.type = BACKLIGHT_RAW;
09461459 204 props.max_brightness = 100;
10b461e4 205 bd = backlight_device_register("nv_backlight", &connector->kdev,
5024c54b 206 nv_encoder, ops, &props);
6ee73861
BS
207 if (IS_ERR(bd))
208 return PTR_ERR(bd);
209
51a3d342 210 drm->backlight = bd;
5024c54b 211 bd->props.brightness = bd->ops->get_brightness(bd);
6ee73861
BS
212 backlight_update_status(bd);
213 return 0;
214}
215
73076481 216int
10b461e4 217nouveau_backlight_init(struct drm_device *dev)
6ee73861 218{
77145f1c 219 struct nouveau_drm *drm = nouveau_drm(dev);
51a3d342 220 struct nouveau_device *device = nv_device(drm->device);
10b461e4 221 struct drm_connector *connector;
6ee73861 222
5bead799
BS
223#ifdef CONFIG_ACPI
224 if (acpi_video_backlight_support()) {
51a3d342 225 NV_INFO(drm, "ACPI backlight interface available, "
5bead799
BS
226 "not registering our own\n");
227 return 0;
228 }
229#endif
230
10b461e4
BS
231 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
232 if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS &&
233 connector->connector_type != DRM_MODE_CONNECTOR_eDP)
234 continue;
235
51a3d342 236 switch (device->card_type) {
10b461e4
BS
237 case NV_40:
238 return nv40_backlight_init(connector);
239 case NV_50:
240 return nv50_backlight_init(connector);
241 default:
242 break;
243 }
6ee73861
BS
244 }
245
10b461e4 246
6ee73861
BS
247 return 0;
248}
249
73076481 250void
10b461e4 251nouveau_backlight_exit(struct drm_device *dev)
6ee73861 252{
77145f1c 253 struct nouveau_drm *drm = nouveau_drm(dev);
6ee73861 254
51a3d342
BS
255 if (drm->backlight) {
256 backlight_device_unregister(drm->backlight);
257 drm->backlight = NULL;
6ee73861
BS
258 }
259}