1 /* SPDX-License-Identifier: MIT
2 *
3 * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
4 */
5 #include <rm/rm.h>
6
7 #include <engine/disp.h>
8 #include <engine/disp/outp.h>
9
10 #include "nvhw/drf.h"
11
12 #include "nvrm/disp.h"
13
14 static int
r570_dmac_alloc(struct nvkm_disp * disp,u32 oclass,int inst,u32 put_offset,struct nvkm_gsp_object * dmac)15 r570_dmac_alloc(struct nvkm_disp *disp, u32 oclass, int inst, u32 put_offset,
16 struct nvkm_gsp_object *dmac)
17 {
18 NV50VAIO_CHANNELDMA_ALLOCATION_PARAMETERS *args;
19
20 args = nvkm_gsp_rm_alloc_get(&disp->rm.object, (oclass << 16) | inst, oclass,
21 sizeof(*args), dmac);
22 if (IS_ERR(args))
23 return PTR_ERR(args);
24
25 args->channelInstance = inst;
26 args->offset = put_offset;
27 args->subDeviceId = BIT(0);
28
29 return nvkm_gsp_rm_alloc_wr(dmac, args);
30 }
31
32 static int
r570_disp_chan_set_pushbuf(struct nvkm_disp * disp,s32 oclass,int inst,struct nvkm_memory * memory)33 r570_disp_chan_set_pushbuf(struct nvkm_disp *disp, s32 oclass, int inst, struct nvkm_memory *memory)
34 {
35 struct nvkm_gsp *gsp = disp->rm.objcom.client->gsp;
36 NV2080_CTRL_INTERNAL_DISPLAY_CHANNEL_PUSHBUFFER_PARAMS *ctrl;
37
38 ctrl = nvkm_gsp_rm_ctrl_get(&gsp->internal.device.subdevice,
39 NV2080_CTRL_CMD_INTERNAL_DISPLAY_CHANNEL_PUSHBUFFER,
40 sizeof(*ctrl));
41 if (IS_ERR(ctrl))
42 return PTR_ERR(ctrl);
43
44 if (memory) {
45 switch (nvkm_memory_target(memory)) {
46 case NVKM_MEM_TARGET_NCOH:
47 ctrl->addressSpace = ADDR_SYSMEM;
48 ctrl->cacheSnoop = 0;
49 ctrl->pbTargetAperture = PHYS_PCI;
50 break;
51 case NVKM_MEM_TARGET_HOST:
52 ctrl->addressSpace = ADDR_SYSMEM;
53 ctrl->cacheSnoop = 1;
54 ctrl->pbTargetAperture = PHYS_PCI_COHERENT;
55 break;
56 case NVKM_MEM_TARGET_VRAM:
57 ctrl->addressSpace = ADDR_FBMEM;
58 ctrl->pbTargetAperture = PHYS_NVM;
59 break;
60 default:
61 WARN_ON(1);
62 return -EINVAL;
63 }
64
65 ctrl->physicalAddr = nvkm_memory_addr(memory);
66 ctrl->limit = nvkm_memory_size(memory) - 1;
67 }
68
69 ctrl->hclass = oclass;
70 ctrl->channelInstance = inst;
71 ctrl->valid = ((oclass & 0xff) != 0x7a) ? 1 : 0;
72 ctrl->subDeviceId = BIT(0);
73
74 return nvkm_gsp_rm_ctrl_wr(&gsp->internal.device.subdevice, ctrl);
75 }
76
77 static int
r570_dp_set_indexed_link_rates(struct nvkm_outp * outp)78 r570_dp_set_indexed_link_rates(struct nvkm_outp *outp)
79 {
80 NV0073_CTRL_CMD_DP_CONFIG_INDEXED_LINK_RATES_PARAMS *ctrl;
81 struct nvkm_disp *disp = outp->disp;
82
83 if (WARN_ON(outp->dp.rates > ARRAY_SIZE(ctrl->linkRateTbl)))
84 return -EINVAL;
85
86 ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
87 NV0073_CTRL_CMD_DP_CONFIG_INDEXED_LINK_RATES, sizeof(*ctrl));
88 if (IS_ERR(ctrl))
89 return PTR_ERR(ctrl);
90
91 ctrl->displayId = BIT(outp->index);
92 for (int i = 0; i < outp->dp.rates; i++)
93 ctrl->linkRateTbl[outp->dp.rate[i].dpcd] = outp->dp.rate[i].rate * 10 / 200;
94
95 return nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);
96 }
97
98 static int
r570_dp_get_caps(struct nvkm_disp * disp,int * plink_bw,bool * pmst,bool * pwm)99 r570_dp_get_caps(struct nvkm_disp *disp, int *plink_bw, bool *pmst, bool *pwm)
100 {
101 NV0073_CTRL_CMD_DP_GET_CAPS_PARAMS *ctrl;
102 int ret;
103
104 ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
105 NV0073_CTRL_CMD_DP_GET_CAPS, sizeof(*ctrl));
106 if (IS_ERR(ctrl))
107 return PTR_ERR(ctrl);
108
109 ctrl->sorIndex = ~0;
110
111 ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
112 if (ret) {
113 nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
114 return ret;
115 }
116
117 switch (NVVAL_GET(ctrl->maxLinkRate, NV0073_CTRL_CMD, DP_GET_CAPS, MAX_LINK_RATE)) {
118 case NV0073_CTRL_CMD_DP_GET_CAPS_MAX_LINK_RATE_1_62:
119 *plink_bw = 0x06;
120 break;
121 case NV0073_CTRL_CMD_DP_GET_CAPS_MAX_LINK_RATE_2_70:
122 *plink_bw = 0x0a;
123 break;
124 case NV0073_CTRL_CMD_DP_GET_CAPS_MAX_LINK_RATE_5_40:
125 *plink_bw = 0x14;
126 break;
127 case NV0073_CTRL_CMD_DP_GET_CAPS_MAX_LINK_RATE_8_10:
128 *plink_bw = 0x1e;
129 break;
130 default:
131 *plink_bw = 0x00;
132 break;
133 }
134
135 *pmst = ctrl->bIsMultistreamSupported;
136 *pwm = ctrl->bHasIncreasedWatermarkLimits;
137 nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
138 return 0;
139 }
140
141 static int
r570_bl_ctrl(struct nvkm_disp * disp,unsigned display_id,bool set,int * pval)142 r570_bl_ctrl(struct nvkm_disp *disp, unsigned display_id, bool set, int *pval)
143 {
144 u32 cmd = set ? NV0073_CTRL_CMD_SPECIFIC_SET_BACKLIGHT_BRIGHTNESS :
145 NV0073_CTRL_CMD_SPECIFIC_GET_BACKLIGHT_BRIGHTNESS;
146 NV0073_CTRL_SPECIFIC_BACKLIGHT_BRIGHTNESS_PARAMS *ctrl;
147 int ret;
148
149 ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom, cmd, sizeof(*ctrl));
150 if (IS_ERR(ctrl))
151 return PTR_ERR(ctrl);
152
153 ctrl->displayId = BIT(display_id);
154 ctrl->brightness = *pval;
155 ctrl->brightnessType = NV0073_CTRL_SPECIFIC_BACKLIGHT_BRIGHTNESS_TYPE_PERCENT100;
156
157 ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
158 if (ret)
159 return ret;
160
161 *pval = ctrl->brightness;
162
163 nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
164 return 0;
165 }
166
167 static int
r570_disp_get_active(struct nvkm_disp * disp,unsigned head,u32 * displayid)168 r570_disp_get_active(struct nvkm_disp *disp, unsigned head, u32 *displayid)
169 {
170 NV0073_CTRL_SYSTEM_GET_ACTIVE_PARAMS *ctrl;
171 int ret;
172
173 ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
174 NV0073_CTRL_CMD_SYSTEM_GET_ACTIVE, sizeof(*ctrl));
175 if (IS_ERR(ctrl))
176 return PTR_ERR(ctrl);
177
178 ctrl->subDeviceInstance = 0;
179 ctrl->head = head;
180
181 ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
182 if (ret) {
183 nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
184 return ret;
185 }
186
187 *displayid = ctrl->displayId;
188 nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
189 return 0;
190 }
191 static int
r570_disp_get_connect_state(struct nvkm_disp * disp,unsigned display_id)192 r570_disp_get_connect_state(struct nvkm_disp *disp, unsigned display_id)
193 {
194 NV0073_CTRL_SYSTEM_GET_CONNECT_STATE_PARAMS *ctrl;
195 int ret;
196
197 ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
198 NV0073_CTRL_CMD_SYSTEM_GET_CONNECT_STATE, sizeof(*ctrl));
199 if (IS_ERR(ctrl))
200 return PTR_ERR(ctrl);
201
202 ctrl->subDeviceInstance = 0;
203 ctrl->displayMask = BIT(display_id);
204
205 ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
206 if (ret == 0 && (ctrl->displayMask & BIT(display_id)))
207 ret = 1;
208
209 nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
210 return ret;
211 }
212
213 static int
r570_disp_get_supported(struct nvkm_disp * disp,unsigned long * pmask)214 r570_disp_get_supported(struct nvkm_disp *disp, unsigned long *pmask)
215 {
216 NV0073_CTRL_SYSTEM_GET_SUPPORTED_PARAMS *ctrl;
217
218 ctrl = nvkm_gsp_rm_ctrl_rd(&disp->rm.objcom,
219 NV0073_CTRL_CMD_SYSTEM_GET_SUPPORTED, sizeof(*ctrl));
220 if (IS_ERR(ctrl))
221 return PTR_ERR(ctrl);
222
223 *pmask = ctrl->displayMask;
224
225 nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
226 return 0;
227 }
228
229 static int
r570_disp_get_static_info(struct nvkm_disp * disp)230 r570_disp_get_static_info(struct nvkm_disp *disp)
231 {
232 NV2080_CTRL_INTERNAL_DISPLAY_GET_STATIC_INFO_PARAMS *ctrl;
233 struct nvkm_gsp *gsp = disp->engine.subdev.device->gsp;
234
235 ctrl = nvkm_gsp_rm_ctrl_rd(&gsp->internal.device.subdevice,
236 NV2080_CTRL_CMD_INTERNAL_DISPLAY_GET_STATIC_INFO,
237 sizeof(*ctrl));
238 if (IS_ERR(ctrl))
239 return PTR_ERR(ctrl);
240
241 disp->wndw.mask = ctrl->windowPresentMask;
242 disp->wndw.nr = fls(disp->wndw.mask);
243
244 nvkm_gsp_rm_ctrl_done(&gsp->internal.device.subdevice, ctrl);
245 return 0;
246 }
247
248 const struct nvkm_rm_api_disp
249 r570_disp = {
250 .get_static_info = r570_disp_get_static_info,
251 .get_supported = r570_disp_get_supported,
252 .get_connect_state = r570_disp_get_connect_state,
253 .get_active = r570_disp_get_active,
254 .bl_ctrl = r570_bl_ctrl,
255 .dp = {
256 .get_caps = r570_dp_get_caps,
257 .set_indexed_link_rates = r570_dp_set_indexed_link_rates,
258 },
259 .chan = {
260 .set_pushbuf = r570_disp_chan_set_pushbuf,
261 .dmac_alloc = r570_dmac_alloc,
262 },
263 };
264