diff options
| author | Dave Airlie <airlied@redhat.com> | 2018-10-10 20:23:11 -0400 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2018-10-10 20:24:28 -0400 |
| commit | 7e6191d4360a2df6cf2a2613dcb79680cb943df8 (patch) | |
| tree | e07605113d5028f3dd825d6e259f63cdb3f1d161 /drivers | |
| parent | 62e681f7dcab746412dce22d4b75b32c5ea38cdb (diff) | |
| parent | 74a07c0a59fa372b069d879971ba4d9e341979cf (diff) | |
Merge branch 'linux-4.20' of git://github.com/skeggsb/linux into drm-next
Just initial HDMI 2.0 support, and a bunch of other cleanups.
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Ben Skeggs <bskeggs@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/CABDvA=mgEm9JxP7AX7Sff-AEs7a75M4SqwFHmLPZhJojm4k=OA@mail.gmail.com
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/disp.c | 40 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/include/nvif/cl5070.h | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_backlight.c | 220 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_connector.c | 54 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_connector.h | 33 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.h | 25 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.c | 179 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigm200.c | 36 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h | 8 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c | 11 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgv100.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c | 1 |
17 files changed, 401 insertions, 236 deletions
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 1dbd1dcdcf15..5f163a025e89 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <drm/drm_dp_helper.h> | 36 | #include <drm/drm_dp_helper.h> |
| 37 | #include <drm/drm_fb_helper.h> | 37 | #include <drm/drm_fb_helper.h> |
| 38 | #include <drm/drm_plane_helper.h> | 38 | #include <drm/drm_plane_helper.h> |
| 39 | #include <drm/drm_scdc_helper.h> | ||
| 39 | #include <drm/drm_edid.h> | 40 | #include <drm/drm_edid.h> |
| 40 | 41 | ||
| 41 | #include <nvif/class.h> | 42 | #include <nvif/class.h> |
| @@ -531,6 +532,7 @@ nv50_hdmi_disable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc) | |||
| 531 | static void | 532 | static void |
| 532 | nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) | 533 | nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) |
| 533 | { | 534 | { |
| 535 | struct nouveau_drm *drm = nouveau_drm(encoder->dev); | ||
| 534 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | 536 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
| 535 | struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); | 537 | struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); |
| 536 | struct nv50_disp *disp = nv50_disp(encoder->dev); | 538 | struct nv50_disp *disp = nv50_disp(encoder->dev); |
| @@ -548,9 +550,12 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) | |||
| 548 | .pwr.rekey = 56, /* binary driver, and tegra, constant */ | 550 | .pwr.rekey = 56, /* binary driver, and tegra, constant */ |
| 549 | }; | 551 | }; |
| 550 | struct nouveau_connector *nv_connector; | 552 | struct nouveau_connector *nv_connector; |
| 553 | struct drm_hdmi_info *hdmi; | ||
| 551 | u32 max_ac_packet; | 554 | u32 max_ac_packet; |
| 552 | union hdmi_infoframe avi_frame; | 555 | union hdmi_infoframe avi_frame; |
| 553 | union hdmi_infoframe vendor_frame; | 556 | union hdmi_infoframe vendor_frame; |
| 557 | bool scdc_supported, high_tmds_clock_ratio = false, scrambling = false; | ||
| 558 | u8 config; | ||
| 554 | int ret; | 559 | int ret; |
| 555 | int size; | 560 | int size; |
| 556 | 561 | ||
| @@ -558,8 +563,11 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) | |||
| 558 | if (!drm_detect_hdmi_monitor(nv_connector->edid)) | 563 | if (!drm_detect_hdmi_monitor(nv_connector->edid)) |
| 559 | return; | 564 | return; |
| 560 | 565 | ||
| 566 | hdmi = &nv_connector->base.display_info.hdmi; | ||
| 567 | scdc_supported = hdmi->scdc.supported; | ||
| 568 | |||
| 561 | ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, mode, | 569 | ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, mode, |
| 562 | false); | 570 | scdc_supported); |
| 563 | if (!ret) { | 571 | if (!ret) { |
| 564 | /* We have an AVI InfoFrame, populate it to the display */ | 572 | /* We have an AVI InfoFrame, populate it to the display */ |
| 565 | args.pwr.avi_infoframe_length | 573 | args.pwr.avi_infoframe_length |
| @@ -582,12 +590,42 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) | |||
| 582 | max_ac_packet -= 18; /* constant from tegra */ | 590 | max_ac_packet -= 18; /* constant from tegra */ |
| 583 | args.pwr.max_ac_packet = max_ac_packet / 32; | 591 | args.pwr.max_ac_packet = max_ac_packet / 32; |
| 584 | 592 | ||
| 593 | if (hdmi->scdc.scrambling.supported) { | ||
| 594 | high_tmds_clock_ratio = mode->clock > 340000; | ||
| 595 | scrambling = high_tmds_clock_ratio || | ||
| 596 | hdmi->scdc.scrambling.low_rates; | ||
| 597 | } | ||
| 598 | |||
| 599 | args.pwr.scdc = | ||
| 600 | NV50_DISP_SOR_HDMI_PWR_V0_SCDC_SCRAMBLE * scrambling | | ||
| 601 | NV50_DISP_SOR_HDMI_PWR_V0_SCDC_DIV_BY_4 * high_tmds_clock_ratio; | ||
| 602 | |||
| 585 | size = sizeof(args.base) | 603 | size = sizeof(args.base) |
| 586 | + sizeof(args.pwr) | 604 | + sizeof(args.pwr) |
| 587 | + args.pwr.avi_infoframe_length | 605 | + args.pwr.avi_infoframe_length |
| 588 | + args.pwr.vendor_infoframe_length; | 606 | + args.pwr.vendor_infoframe_length; |
| 589 | nvif_mthd(&disp->disp->object, 0, &args, size); | 607 | nvif_mthd(&disp->disp->object, 0, &args, size); |
| 608 | |||
| 590 | nv50_audio_enable(encoder, mode); | 609 | nv50_audio_enable(encoder, mode); |
| 610 | |||
| 611 | /* If SCDC is supported by the downstream monitor, update | ||
| 612 | * divider / scrambling settings to what we programmed above. | ||
| 613 | */ | ||
| 614 | if (!hdmi->scdc.scrambling.supported) | ||
| 615 | return; | ||
| 616 | |||
| 617 | ret = drm_scdc_readb(nv_encoder->i2c, SCDC_TMDS_CONFIG, &config); | ||
| 618 | if (ret < 0) { | ||
| 619 | NV_ERROR(drm, "Failure to read SCDC_TMDS_CONFIG: %d\n", ret); | ||
| 620 | return; | ||
| 621 | } | ||
| 622 | config &= ~(SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE); | ||
| 623 | config |= SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 * high_tmds_clock_ratio; | ||
| 624 | config |= SCDC_SCRAMBLING_ENABLE * scrambling; | ||
| 625 | ret = drm_scdc_writeb(nv_encoder->i2c, SCDC_TMDS_CONFIG, config); | ||
| 626 | if (ret < 0) | ||
| 627 | NV_ERROR(drm, "Failure to write SCDC_TMDS_CONFIG = 0x%02x: %d\n", | ||
| 628 | config, ret); | ||
| 591 | } | 629 | } |
| 592 | 630 | ||
| 593 | /****************************************************************************** | 631 | /****************************************************************************** |
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h index 7cdf53615d7b..bced81987269 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h +++ b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h | |||
| @@ -69,7 +69,10 @@ struct nv50_disp_sor_hdmi_pwr_v0 { | |||
| 69 | __u8 rekey; | 69 | __u8 rekey; |
| 70 | __u8 avi_infoframe_length; | 70 | __u8 avi_infoframe_length; |
| 71 | __u8 vendor_infoframe_length; | 71 | __u8 vendor_infoframe_length; |
| 72 | __u8 pad06[2]; | 72 | #define NV50_DISP_SOR_HDMI_PWR_V0_SCDC_SCRAMBLE (1 << 0) |
| 73 | #define NV50_DISP_SOR_HDMI_PWR_V0_SCDC_DIV_BY_4 (1 << 1) | ||
| 74 | __u8 scdc; | ||
| 75 | __u8 pad07[1]; | ||
| 73 | }; | 76 | }; |
| 74 | 77 | ||
| 75 | struct nv50_disp_sor_lvds_script_v0 { | 78 | struct nv50_disp_sor_lvds_script_v0 { |
diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index 408b955e5c39..5f5be6368aed 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c | |||
| @@ -37,18 +37,19 @@ | |||
| 37 | #include "nouveau_drv.h" | 37 | #include "nouveau_drv.h" |
| 38 | #include "nouveau_reg.h" | 38 | #include "nouveau_reg.h" |
| 39 | #include "nouveau_encoder.h" | 39 | #include "nouveau_encoder.h" |
| 40 | #include "nouveau_connector.h" | ||
| 40 | 41 | ||
| 41 | static struct ida bl_ida; | 42 | static struct ida bl_ida; |
| 42 | #define BL_NAME_SIZE 15 // 12 for name + 2 for digits + 1 for '\0' | 43 | #define BL_NAME_SIZE 15 // 12 for name + 2 for digits + 1 for '\0' |
| 43 | 44 | ||
| 44 | struct backlight_connector { | 45 | struct nouveau_backlight { |
| 45 | struct list_head head; | 46 | struct backlight_device *dev; |
| 46 | int id; | 47 | int id; |
| 47 | }; | 48 | }; |
| 48 | 49 | ||
| 49 | static bool | 50 | static bool |
| 50 | nouveau_get_backlight_name(char backlight_name[BL_NAME_SIZE], struct backlight_connector | 51 | nouveau_get_backlight_name(char backlight_name[BL_NAME_SIZE], |
| 51 | *connector) | 52 | struct nouveau_backlight *bl) |
| 52 | { | 53 | { |
| 53 | const int nb = ida_simple_get(&bl_ida, 0, 0, GFP_KERNEL); | 54 | const int nb = ida_simple_get(&bl_ida, 0, 0, GFP_KERNEL); |
| 54 | if (nb < 0 || nb >= 100) | 55 | if (nb < 0 || nb >= 100) |
| @@ -57,17 +58,18 @@ nouveau_get_backlight_name(char backlight_name[BL_NAME_SIZE], struct backlight_c | |||
| 57 | snprintf(backlight_name, BL_NAME_SIZE, "nv_backlight%d", nb); | 58 | snprintf(backlight_name, BL_NAME_SIZE, "nv_backlight%d", nb); |
| 58 | else | 59 | else |
| 59 | snprintf(backlight_name, BL_NAME_SIZE, "nv_backlight"); | 60 | snprintf(backlight_name, BL_NAME_SIZE, "nv_backlight"); |
| 60 | connector->id = nb; | 61 | bl->id = nb; |
| 61 | return true; | 62 | return true; |
| 62 | } | 63 | } |
| 63 | 64 | ||
| 64 | static int | 65 | static int |
| 65 | nv40_get_intensity(struct backlight_device *bd) | 66 | nv40_get_intensity(struct backlight_device *bd) |
| 66 | { | 67 | { |
| 67 | struct nouveau_drm *drm = bl_get_data(bd); | 68 | struct nouveau_encoder *nv_encoder = bl_get_data(bd); |
| 69 | struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); | ||
| 68 | struct nvif_object *device = &drm->client.device.object; | 70 | struct nvif_object *device = &drm->client.device.object; |
| 69 | int val = (nvif_rd32(device, NV40_PMC_BACKLIGHT) & | 71 | int val = (nvif_rd32(device, NV40_PMC_BACKLIGHT) & |
| 70 | NV40_PMC_BACKLIGHT_MASK) >> 16; | 72 | NV40_PMC_BACKLIGHT_MASK) >> 16; |
| 71 | 73 | ||
| 72 | return val; | 74 | return val; |
| 73 | } | 75 | } |
| @@ -75,13 +77,14 @@ nv40_get_intensity(struct backlight_device *bd) | |||
| 75 | static int | 77 | static int |
| 76 | nv40_set_intensity(struct backlight_device *bd) | 78 | nv40_set_intensity(struct backlight_device *bd) |
| 77 | { | 79 | { |
| 78 | struct nouveau_drm *drm = bl_get_data(bd); | 80 | struct nouveau_encoder *nv_encoder = bl_get_data(bd); |
| 81 | struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); | ||
| 79 | struct nvif_object *device = &drm->client.device.object; | 82 | struct nvif_object *device = &drm->client.device.object; |
| 80 | int val = bd->props.brightness; | 83 | int val = bd->props.brightness; |
| 81 | int reg = nvif_rd32(device, NV40_PMC_BACKLIGHT); | 84 | int reg = nvif_rd32(device, NV40_PMC_BACKLIGHT); |
| 82 | 85 | ||
| 83 | nvif_wr32(device, NV40_PMC_BACKLIGHT, | 86 | nvif_wr32(device, NV40_PMC_BACKLIGHT, |
| 84 | (val << 16) | (reg & ~NV40_PMC_BACKLIGHT_MASK)); | 87 | (val << 16) | (reg & ~NV40_PMC_BACKLIGHT_MASK)); |
| 85 | 88 | ||
| 86 | return 0; | 89 | return 0; |
| 87 | } | 90 | } |
| @@ -93,38 +96,19 @@ static const struct backlight_ops nv40_bl_ops = { | |||
| 93 | }; | 96 | }; |
| 94 | 97 | ||
| 95 | static int | 98 | static int |
| 96 | nv40_backlight_init(struct drm_connector *connector) | 99 | nv40_backlight_init(struct nouveau_encoder *encoder, |
| 100 | struct backlight_properties *props, | ||
| 101 | const struct backlight_ops **ops) | ||
| 97 | { | 102 | { |
| 98 | struct nouveau_drm *drm = nouveau_drm(connector->dev); | 103 | struct nouveau_drm *drm = nouveau_drm(encoder->base.base.dev); |
| 99 | struct nvif_object *device = &drm->client.device.object; | 104 | struct nvif_object *device = &drm->client.device.object; |
| 100 | struct backlight_properties props; | ||
| 101 | struct backlight_device *bd; | ||
| 102 | struct backlight_connector bl_connector; | ||
| 103 | char backlight_name[BL_NAME_SIZE]; | ||
| 104 | 105 | ||
| 105 | if (!(nvif_rd32(device, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK)) | 106 | if (!(nvif_rd32(device, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK)) |
| 106 | return 0; | 107 | return -ENODEV; |
| 107 | |||
| 108 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
| 109 | props.type = BACKLIGHT_RAW; | ||
| 110 | props.max_brightness = 31; | ||
| 111 | if (!nouveau_get_backlight_name(backlight_name, &bl_connector)) { | ||
| 112 | NV_ERROR(drm, "Failed to retrieve a unique name for the backlight interface\n"); | ||
| 113 | return 0; | ||
| 114 | } | ||
| 115 | bd = backlight_device_register(backlight_name , connector->kdev, drm, | ||
| 116 | &nv40_bl_ops, &props); | ||
| 117 | |||
| 118 | if (IS_ERR(bd)) { | ||
| 119 | if (bl_connector.id > 0) | ||
| 120 | ida_simple_remove(&bl_ida, bl_connector.id); | ||
| 121 | return PTR_ERR(bd); | ||
| 122 | } | ||
| 123 | list_add(&bl_connector.head, &drm->bl_connectors); | ||
| 124 | drm->backlight = bd; | ||
| 125 | bd->props.brightness = nv40_get_intensity(bd); | ||
| 126 | backlight_update_status(bd); | ||
| 127 | 108 | ||
| 109 | props->type = BACKLIGHT_RAW; | ||
| 110 | props->max_brightness = 31; | ||
| 111 | *ops = &nv40_bl_ops; | ||
| 128 | return 0; | 112 | return 0; |
| 129 | } | 113 | } |
| 130 | 114 | ||
| @@ -154,7 +138,7 @@ nv50_set_intensity(struct backlight_device *bd) | |||
| 154 | u32 val = (bd->props.brightness * div) / 100; | 138 | u32 val = (bd->props.brightness * div) / 100; |
| 155 | 139 | ||
| 156 | nvif_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), | 140 | nvif_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), |
| 157 | NV50_PDISP_SOR_PWM_CTL_NEW | val); | 141 | NV50_PDISP_SOR_PWM_CTL_NEW | val); |
| 158 | return 0; | 142 | return 0; |
| 159 | } | 143 | } |
| 160 | 144 | ||
| @@ -194,9 +178,10 @@ nva3_set_intensity(struct backlight_device *bd) | |||
| 194 | div = nvif_rd32(device, NV50_PDISP_SOR_PWM_DIV(or)); | 178 | div = nvif_rd32(device, NV50_PDISP_SOR_PWM_DIV(or)); |
| 195 | val = (bd->props.brightness * div) / 100; | 179 | val = (bd->props.brightness * div) / 100; |
| 196 | if (div) { | 180 | if (div) { |
| 197 | nvif_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), val | | 181 | nvif_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), |
| 198 | NV50_PDISP_SOR_PWM_CTL_NEW | | 182 | val | |
| 199 | NVA3_PDISP_SOR_PWM_CTL_UNK); | 183 | NV50_PDISP_SOR_PWM_CTL_NEW | |
| 184 | NVA3_PDISP_SOR_PWM_CTL_UNK); | ||
| 200 | return 0; | 185 | return 0; |
| 201 | } | 186 | } |
| 202 | 187 | ||
| @@ -210,110 +195,119 @@ static const struct backlight_ops nva3_bl_ops = { | |||
| 210 | }; | 195 | }; |
| 211 | 196 | ||
| 212 | static int | 197 | static int |
| 213 | nv50_backlight_init(struct drm_connector *connector) | 198 | nv50_backlight_init(struct nouveau_encoder *nv_encoder, |
| 199 | struct backlight_properties *props, | ||
| 200 | const struct backlight_ops **ops) | ||
| 214 | { | 201 | { |
| 215 | struct nouveau_drm *drm = nouveau_drm(connector->dev); | 202 | struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); |
| 216 | struct nvif_object *device = &drm->client.device.object; | 203 | struct nvif_object *device = &drm->client.device.object; |
| 217 | struct nouveau_encoder *nv_encoder; | ||
| 218 | struct backlight_properties props; | ||
| 219 | struct backlight_device *bd; | ||
| 220 | const struct backlight_ops *ops; | ||
| 221 | struct backlight_connector bl_connector; | ||
| 222 | char backlight_name[BL_NAME_SIZE]; | ||
| 223 | |||
| 224 | nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS); | ||
| 225 | if (!nv_encoder) { | ||
| 226 | nv_encoder = find_encoder(connector, DCB_OUTPUT_DP); | ||
| 227 | if (!nv_encoder) | ||
| 228 | return -ENODEV; | ||
| 229 | } | ||
| 230 | 204 | ||
| 231 | if (!nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(ffs(nv_encoder->dcb->or) - 1))) | 205 | if (!nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(ffs(nv_encoder->dcb->or) - 1))) |
| 232 | return 0; | 206 | return -ENODEV; |
| 233 | 207 | ||
| 234 | if (drm->client.device.info.chipset <= 0xa0 || | 208 | if (drm->client.device.info.chipset <= 0xa0 || |
| 235 | drm->client.device.info.chipset == 0xaa || | 209 | drm->client.device.info.chipset == 0xaa || |
| 236 | drm->client.device.info.chipset == 0xac) | 210 | drm->client.device.info.chipset == 0xac) |
| 237 | ops = &nv50_bl_ops; | 211 | *ops = &nv50_bl_ops; |
| 238 | else | 212 | else |
| 239 | ops = &nva3_bl_ops; | 213 | *ops = &nva3_bl_ops; |
| 240 | |||
| 241 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
| 242 | props.type = BACKLIGHT_RAW; | ||
| 243 | props.max_brightness = 100; | ||
| 244 | if (!nouveau_get_backlight_name(backlight_name, &bl_connector)) { | ||
| 245 | NV_ERROR(drm, "Failed to retrieve a unique name for the backlight interface\n"); | ||
| 246 | return 0; | ||
| 247 | } | ||
| 248 | bd = backlight_device_register(backlight_name , connector->kdev, | ||
| 249 | nv_encoder, ops, &props); | ||
| 250 | 214 | ||
| 251 | if (IS_ERR(bd)) { | 215 | props->type = BACKLIGHT_RAW; |
| 252 | if (bl_connector.id > 0) | 216 | props->max_brightness = 100; |
| 253 | ida_simple_remove(&bl_ida, bl_connector.id); | ||
| 254 | return PTR_ERR(bd); | ||
| 255 | } | ||
| 256 | 217 | ||
| 257 | list_add(&bl_connector.head, &drm->bl_connectors); | ||
| 258 | drm->backlight = bd; | ||
| 259 | bd->props.brightness = bd->ops->get_brightness(bd); | ||
| 260 | backlight_update_status(bd); | ||
| 261 | return 0; | 218 | return 0; |
| 262 | } | 219 | } |
| 263 | 220 | ||
| 264 | int | 221 | int |
| 265 | nouveau_backlight_init(struct drm_device *dev) | 222 | nouveau_backlight_init(struct drm_connector *connector) |
| 266 | { | 223 | { |
| 267 | struct nouveau_drm *drm = nouveau_drm(dev); | 224 | struct nouveau_drm *drm = nouveau_drm(connector->dev); |
| 225 | struct nouveau_backlight *bl; | ||
| 226 | struct nouveau_encoder *nv_encoder = NULL; | ||
| 268 | struct nvif_device *device = &drm->client.device; | 227 | struct nvif_device *device = &drm->client.device; |
| 269 | struct drm_connector *connector; | 228 | char backlight_name[BL_NAME_SIZE]; |
| 270 | struct drm_connector_list_iter conn_iter; | 229 | struct backlight_properties props = {0}; |
| 271 | 230 | const struct backlight_ops *ops; | |
| 272 | INIT_LIST_HEAD(&drm->bl_connectors); | 231 | int ret; |
| 273 | 232 | ||
| 274 | if (apple_gmux_present()) { | 233 | if (apple_gmux_present()) { |
| 275 | NV_INFO(drm, "Apple GMUX detected: not registering Nouveau backlight interface\n"); | 234 | NV_INFO_ONCE(drm, "Apple GMUX detected: not registering Nouveau backlight interface\n"); |
| 276 | return 0; | 235 | return 0; |
| 277 | } | 236 | } |
| 278 | 237 | ||
| 279 | drm_connector_list_iter_begin(dev, &conn_iter); | 238 | if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) |
| 280 | drm_for_each_connector_iter(connector, &conn_iter) { | 239 | nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS); |
| 281 | if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && | 240 | else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) |
| 282 | connector->connector_type != DRM_MODE_CONNECTOR_eDP) | 241 | nv_encoder = find_encoder(connector, DCB_OUTPUT_DP); |
| 283 | continue; | 242 | else |
| 284 | 243 | return 0; | |
| 285 | switch (device->info.family) { | 244 | |
| 286 | case NV_DEVICE_INFO_V0_CURIE: | 245 | if (!nv_encoder) |
| 287 | return nv40_backlight_init(connector); | 246 | return 0; |
| 288 | case NV_DEVICE_INFO_V0_TESLA: | 247 | |
| 289 | case NV_DEVICE_INFO_V0_FERMI: | 248 | switch (device->info.family) { |
| 290 | case NV_DEVICE_INFO_V0_KEPLER: | 249 | case NV_DEVICE_INFO_V0_CURIE: |
| 291 | case NV_DEVICE_INFO_V0_MAXWELL: | 250 | ret = nv40_backlight_init(nv_encoder, &props, &ops); |
| 292 | return nv50_backlight_init(connector); | 251 | break; |
| 293 | default: | 252 | case NV_DEVICE_INFO_V0_TESLA: |
| 294 | break; | 253 | case NV_DEVICE_INFO_V0_FERMI: |
| 295 | } | 254 | case NV_DEVICE_INFO_V0_KEPLER: |
| 255 | case NV_DEVICE_INFO_V0_MAXWELL: | ||
| 256 | ret = nv50_backlight_init(nv_encoder, &props, &ops); | ||
| 257 | break; | ||
| 258 | default: | ||
| 259 | return 0; | ||
| 296 | } | 260 | } |
| 297 | drm_connector_list_iter_end(&conn_iter); | 261 | |
| 262 | if (ret == -ENODEV) | ||
| 263 | return 0; | ||
| 264 | else if (ret) | ||
| 265 | return ret; | ||
| 266 | |||
| 267 | bl = kzalloc(sizeof(*bl), GFP_KERNEL); | ||
| 268 | if (!bl) | ||
| 269 | return -ENOMEM; | ||
| 270 | |||
| 271 | if (!nouveau_get_backlight_name(backlight_name, bl)) { | ||
| 272 | NV_ERROR(drm, "Failed to retrieve a unique name for the backlight interface\n"); | ||
| 273 | goto fail_alloc; | ||
| 274 | } | ||
| 275 | |||
| 276 | bl->dev = backlight_device_register(backlight_name, connector->kdev, | ||
| 277 | nv_encoder, ops, &props); | ||
| 278 | if (IS_ERR(bl->dev)) { | ||
| 279 | if (bl->id >= 0) | ||
| 280 | ida_simple_remove(&bl_ida, bl->id); | ||
| 281 | ret = PTR_ERR(bl->dev); | ||
| 282 | goto fail_alloc; | ||
| 283 | } | ||
| 284 | |||
| 285 | nouveau_connector(connector)->backlight = bl; | ||
| 286 | bl->dev->props.brightness = bl->dev->ops->get_brightness(bl->dev); | ||
| 287 | backlight_update_status(bl->dev); | ||
| 298 | 288 | ||
| 299 | return 0; | 289 | return 0; |
| 290 | |||
| 291 | fail_alloc: | ||
| 292 | kfree(bl); | ||
| 293 | return ret; | ||
| 300 | } | 294 | } |
| 301 | 295 | ||
| 302 | void | 296 | void |
| 303 | nouveau_backlight_exit(struct drm_device *dev) | 297 | nouveau_backlight_fini(struct drm_connector *connector) |
| 304 | { | 298 | { |
| 305 | struct nouveau_drm *drm = nouveau_drm(dev); | 299 | struct nouveau_connector *nv_conn = nouveau_connector(connector); |
| 306 | struct backlight_connector *connector; | 300 | struct nouveau_backlight *bl = nv_conn->backlight; |
| 307 | 301 | ||
| 308 | list_for_each_entry(connector, &drm->bl_connectors, head) { | 302 | if (!bl) |
| 309 | if (connector->id >= 0) | 303 | return; |
| 310 | ida_simple_remove(&bl_ida, connector->id); | ||
| 311 | } | ||
| 312 | 304 | ||
| 313 | if (drm->backlight) { | 305 | if (bl->id >= 0) |
| 314 | backlight_device_unregister(drm->backlight); | 306 | ida_simple_remove(&bl_ida, bl->id); |
| 315 | drm->backlight = NULL; | 307 | |
| 316 | } | 308 | backlight_device_unregister(bl->dev); |
| 309 | nv_conn->backlight = NULL; | ||
| 310 | kfree(bl); | ||
| 317 | } | 311 | } |
| 318 | 312 | ||
| 319 | void | 313 | void |
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index dde8724aa8f5..fd80661dff92 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c | |||
| @@ -886,6 +886,22 @@ nouveau_connector_detect_depth(struct drm_connector *connector) | |||
| 886 | } | 886 | } |
| 887 | 887 | ||
| 888 | static int | 888 | static int |
| 889 | nouveau_connector_late_register(struct drm_connector *connector) | ||
| 890 | { | ||
| 891 | int ret; | ||
| 892 | |||
| 893 | ret = nouveau_backlight_init(connector); | ||
| 894 | |||
| 895 | return ret; | ||
| 896 | } | ||
| 897 | |||
| 898 | static void | ||
| 899 | nouveau_connector_early_unregister(struct drm_connector *connector) | ||
| 900 | { | ||
| 901 | nouveau_backlight_fini(connector); | ||
| 902 | } | ||
| 903 | |||
| 904 | static int | ||
| 889 | nouveau_connector_get_modes(struct drm_connector *connector) | 905 | nouveau_connector_get_modes(struct drm_connector *connector) |
| 890 | { | 906 | { |
| 891 | struct drm_device *dev = connector->dev; | 907 | struct drm_device *dev = connector->dev; |
| @@ -953,18 +969,33 @@ nouveau_connector_get_modes(struct drm_connector *connector) | |||
| 953 | } | 969 | } |
| 954 | 970 | ||
| 955 | static unsigned | 971 | static unsigned |
| 956 | get_tmds_link_bandwidth(struct drm_connector *connector, bool hdmi) | 972 | get_tmds_link_bandwidth(struct drm_connector *connector) |
| 957 | { | 973 | { |
| 958 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | 974 | struct nouveau_connector *nv_connector = nouveau_connector(connector); |
| 975 | struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; | ||
| 959 | struct nouveau_drm *drm = nouveau_drm(connector->dev); | 976 | struct nouveau_drm *drm = nouveau_drm(connector->dev); |
| 960 | struct dcb_output *dcb = nv_connector->detected_encoder->dcb; | 977 | struct dcb_output *dcb = nv_connector->detected_encoder->dcb; |
| 978 | struct drm_display_info *info = NULL; | ||
| 979 | const unsigned duallink_scale = | ||
| 980 | nouveau_duallink && nv_encoder->dcb->duallink_possible ? 2 : 1; | ||
| 981 | |||
| 982 | if (drm_detect_hdmi_monitor(nv_connector->edid)) | ||
| 983 | info = &nv_connector->base.display_info; | ||
| 961 | 984 | ||
| 962 | if (hdmi) { | 985 | if (info) { |
| 963 | if (nouveau_hdmimhz > 0) | 986 | if (nouveau_hdmimhz > 0) |
| 964 | return nouveau_hdmimhz * 1000; | 987 | return nouveau_hdmimhz * 1000; |
| 965 | /* Note: these limits are conservative, some Fermi's | 988 | /* Note: these limits are conservative, some Fermi's |
| 966 | * can do 297 MHz. Unclear how this can be determined. | 989 | * can do 297 MHz. Unclear how this can be determined. |
| 967 | */ | 990 | */ |
| 991 | if (drm->client.device.info.chipset >= 0x120) { | ||
| 992 | const int max_tmds_clock = | ||
| 993 | info->hdmi.scdc.scrambling.supported ? | ||
| 994 | 594000 : 340000; | ||
| 995 | return info->max_tmds_clock ? | ||
| 996 | min(info->max_tmds_clock, max_tmds_clock) : | ||
| 997 | max_tmds_clock; | ||
| 998 | } | ||
| 968 | if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_KEPLER) | 999 | if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_KEPLER) |
| 969 | return 297000; | 1000 | return 297000; |
| 970 | if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_FERMI) | 1001 | if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_FERMI) |
| @@ -972,13 +1003,13 @@ get_tmds_link_bandwidth(struct drm_connector *connector, bool hdmi) | |||
| 972 | } | 1003 | } |
| 973 | if (dcb->location != DCB_LOC_ON_CHIP || | 1004 | if (dcb->location != DCB_LOC_ON_CHIP || |
| 974 | drm->client.device.info.chipset >= 0x46) | 1005 | drm->client.device.info.chipset >= 0x46) |
| 975 | return 165000; | 1006 | return 165000 * duallink_scale; |
| 976 | else if (drm->client.device.info.chipset >= 0x40) | 1007 | else if (drm->client.device.info.chipset >= 0x40) |
| 977 | return 155000; | 1008 | return 155000 * duallink_scale; |
| 978 | else if (drm->client.device.info.chipset >= 0x18) | 1009 | else if (drm->client.device.info.chipset >= 0x18) |
| 979 | return 135000; | 1010 | return 135000 * duallink_scale; |
| 980 | else | 1011 | else |
| 981 | return 112000; | 1012 | return 112000 * duallink_scale; |
| 982 | } | 1013 | } |
| 983 | 1014 | ||
| 984 | static enum drm_mode_status | 1015 | static enum drm_mode_status |
| @@ -990,7 +1021,6 @@ nouveau_connector_mode_valid(struct drm_connector *connector, | |||
| 990 | struct drm_encoder *encoder = to_drm_encoder(nv_encoder); | 1021 | struct drm_encoder *encoder = to_drm_encoder(nv_encoder); |
| 991 | unsigned min_clock = 25000, max_clock = min_clock; | 1022 | unsigned min_clock = 25000, max_clock = min_clock; |
| 992 | unsigned clock = mode->clock; | 1023 | unsigned clock = mode->clock; |
| 993 | bool hdmi; | ||
| 994 | 1024 | ||
| 995 | switch (nv_encoder->dcb->type) { | 1025 | switch (nv_encoder->dcb->type) { |
| 996 | case DCB_OUTPUT_LVDS: | 1026 | case DCB_OUTPUT_LVDS: |
| @@ -1003,11 +1033,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector, | |||
| 1003 | max_clock = 400000; | 1033 | max_clock = 400000; |
| 1004 | break; | 1034 | break; |
| 1005 | case DCB_OUTPUT_TMDS: | 1035 | case DCB_OUTPUT_TMDS: |
| 1006 | hdmi = drm_detect_hdmi_monitor(nv_connector->edid); | 1036 | max_clock = get_tmds_link_bandwidth(connector); |
| 1007 | max_clock = get_tmds_link_bandwidth(connector, hdmi); | ||
| 1008 | if (!hdmi && nouveau_duallink && | ||
| 1009 | nv_encoder->dcb->duallink_possible) | ||
| 1010 | max_clock *= 2; | ||
| 1011 | break; | 1037 | break; |
| 1012 | case DCB_OUTPUT_ANALOG: | 1038 | case DCB_OUTPUT_ANALOG: |
| 1013 | max_clock = nv_encoder->dcb->crtconf.maxfreq; | 1039 | max_clock = nv_encoder->dcb->crtconf.maxfreq; |
| @@ -1069,6 +1095,8 @@ nouveau_connector_funcs = { | |||
| 1069 | .atomic_destroy_state = nouveau_conn_atomic_destroy_state, | 1095 | .atomic_destroy_state = nouveau_conn_atomic_destroy_state, |
| 1070 | .atomic_set_property = nouveau_conn_atomic_set_property, | 1096 | .atomic_set_property = nouveau_conn_atomic_set_property, |
| 1071 | .atomic_get_property = nouveau_conn_atomic_get_property, | 1097 | .atomic_get_property = nouveau_conn_atomic_get_property, |
| 1098 | .late_register = nouveau_connector_late_register, | ||
| 1099 | .early_unregister = nouveau_connector_early_unregister, | ||
| 1072 | }; | 1100 | }; |
| 1073 | 1101 | ||
| 1074 | static const struct drm_connector_funcs | 1102 | static const struct drm_connector_funcs |
| @@ -1084,6 +1112,8 @@ nouveau_connector_funcs_lvds = { | |||
| 1084 | .atomic_destroy_state = nouveau_conn_atomic_destroy_state, | 1112 | .atomic_destroy_state = nouveau_conn_atomic_destroy_state, |
| 1085 | .atomic_set_property = nouveau_conn_atomic_set_property, | 1113 | .atomic_set_property = nouveau_conn_atomic_set_property, |
| 1086 | .atomic_get_property = nouveau_conn_atomic_get_property, | 1114 | .atomic_get_property = nouveau_conn_atomic_get_property, |
| 1115 | .late_register = nouveau_connector_late_register, | ||
| 1116 | .early_unregister = nouveau_connector_early_unregister, | ||
| 1087 | }; | 1117 | }; |
| 1088 | 1118 | ||
| 1089 | static int | 1119 | static int |
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index 0acc07555bcd..f57ef35b1e5e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h | |||
| @@ -39,6 +39,10 @@ | |||
| 39 | 39 | ||
| 40 | struct nvkm_i2c_port; | 40 | struct nvkm_i2c_port; |
| 41 | 41 | ||
| 42 | #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT | ||
| 43 | struct nouveau_backlight; | ||
| 44 | #endif | ||
| 45 | |||
| 42 | struct nouveau_connector { | 46 | struct nouveau_connector { |
| 43 | struct drm_connector base; | 47 | struct drm_connector base; |
| 44 | enum dcb_connector_type type; | 48 | enum dcb_connector_type type; |
| @@ -55,6 +59,9 @@ struct nouveau_connector { | |||
| 55 | struct nouveau_encoder *detected_encoder; | 59 | struct nouveau_encoder *detected_encoder; |
| 56 | struct edid *edid; | 60 | struct edid *edid; |
| 57 | struct drm_display_mode *native_mode; | 61 | struct drm_display_mode *native_mode; |
| 62 | #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT | ||
| 63 | struct nouveau_backlight *backlight; | ||
| 64 | #endif | ||
| 58 | }; | 65 | }; |
| 59 | 66 | ||
| 60 | static inline struct nouveau_connector *nouveau_connector( | 67 | static inline struct nouveau_connector *nouveau_connector( |
| @@ -181,4 +188,30 @@ int nouveau_conn_atomic_get_property(struct drm_connector *, | |||
| 181 | const struct drm_connector_state *, | 188 | const struct drm_connector_state *, |
| 182 | struct drm_property *, u64 *); | 189 | struct drm_property *, u64 *); |
| 183 | struct drm_display_mode *nouveau_conn_native_mode(struct drm_connector *); | 190 | struct drm_display_mode *nouveau_conn_native_mode(struct drm_connector *); |
| 191 | |||
| 192 | #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT | ||
| 193 | extern int nouveau_backlight_init(struct drm_connector *); | ||
| 194 | extern void nouveau_backlight_fini(struct drm_connector *); | ||
| 195 | extern void nouveau_backlight_ctor(void); | ||
| 196 | extern void nouveau_backlight_dtor(void); | ||
| 197 | #else | ||
| 198 | static inline int | ||
| 199 | nouveau_backlight_init(struct drm_connector *connector) | ||
| 200 | { | ||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | |||
| 204 | static inline void | ||
| 205 | nouveau_backlight_fini(struct drm_connector *connector) { | ||
| 206 | } | ||
| 207 | |||
| 208 | static inline void | ||
| 209 | nouveau_backlight_ctor(void) { | ||
| 210 | } | ||
| 211 | |||
| 212 | static inline void | ||
| 213 | nouveau_backlight_dtor(void) { | ||
| 214 | } | ||
| 215 | #endif | ||
| 216 | |||
| 184 | #endif /* __NOUVEAU_CONNECTOR_H__ */ | 217 | #endif /* __NOUVEAU_CONNECTOR_H__ */ |
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 540c0cbbfcee..f326ffd86766 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
| @@ -582,7 +582,6 @@ nouveau_display_create(struct drm_device *dev) | |||
| 582 | goto vblank_err; | 582 | goto vblank_err; |
| 583 | } | 583 | } |
| 584 | 584 | ||
| 585 | nouveau_backlight_init(dev); | ||
| 586 | INIT_WORK(&drm->hpd_work, nouveau_display_hpd_work); | 585 | INIT_WORK(&drm->hpd_work, nouveau_display_hpd_work); |
| 587 | #ifdef CONFIG_ACPI | 586 | #ifdef CONFIG_ACPI |
| 588 | drm->acpi_nb.notifier_call = nouveau_display_acpi_ntfy; | 587 | drm->acpi_nb.notifier_call = nouveau_display_acpi_ntfy; |
| @@ -607,7 +606,6 @@ nouveau_display_destroy(struct drm_device *dev) | |||
| 607 | #ifdef CONFIG_ACPI | 606 | #ifdef CONFIG_ACPI |
| 608 | unregister_acpi_notifier(&nouveau_drm(dev)->acpi_nb); | 607 | unregister_acpi_notifier(&nouveau_drm(dev)->acpi_nb); |
| 609 | #endif | 608 | #endif |
| 610 | nouveau_backlight_exit(dev); | ||
| 611 | nouveau_display_vblank_fini(dev); | 609 | nouveau_display_vblank_fini(dev); |
| 612 | 610 | ||
| 613 | drm_kms_helper_poll_fini(dev); | 611 | drm_kms_helper_poll_fini(dev); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index ff92b54ce448..eb77e41c2d4e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h | |||
| @@ -85,31 +85,6 @@ int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *, | |||
| 85 | 85 | ||
| 86 | void nouveau_hdmi_mode_set(struct drm_encoder *, struct drm_display_mode *); | 86 | void nouveau_hdmi_mode_set(struct drm_encoder *, struct drm_display_mode *); |
| 87 | 87 | ||
| 88 | #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT | ||
| 89 | extern int nouveau_backlight_init(struct drm_device *); | ||
| 90 | extern void nouveau_backlight_exit(struct drm_device *); | ||
| 91 | extern void nouveau_backlight_ctor(void); | ||
| 92 | extern void nouveau_backlight_dtor(void); | ||
| 93 | #else | ||
| 94 | static inline int | ||
| 95 | nouveau_backlight_init(struct drm_device *dev) | ||
| 96 | { | ||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | static inline void | ||
| 101 | nouveau_backlight_exit(struct drm_device *dev) { | ||
| 102 | } | ||
| 103 | |||
| 104 | static inline void | ||
| 105 | nouveau_backlight_ctor(void) { | ||
| 106 | } | ||
| 107 | |||
| 108 | static inline void | ||
| 109 | nouveau_backlight_dtor(void) { | ||
| 110 | } | ||
| 111 | #endif | ||
| 112 | |||
| 113 | struct drm_framebuffer * | 88 | struct drm_framebuffer * |
| 114 | nouveau_user_framebuffer_create(struct drm_device *, struct drm_file *, | 89 | nouveau_user_framebuffer_create(struct drm_device *, struct drm_file *, |
| 115 | const struct drm_mode_fb_cmd2 *); | 90 | const struct drm_mode_fb_cmd2 *); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 74d2283f2c28..2b2baf6e0e0d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
| @@ -458,75 +458,8 @@ nouveau_accel_init(struct nouveau_drm *drm) | |||
| 458 | nouveau_bo_move_init(drm); | 458 | nouveau_bo_move_init(drm); |
| 459 | } | 459 | } |
| 460 | 460 | ||
| 461 | static int nouveau_drm_probe(struct pci_dev *pdev, | ||
| 462 | const struct pci_device_id *pent) | ||
| 463 | { | ||
| 464 | struct nvkm_device *device; | ||
| 465 | struct apertures_struct *aper; | ||
| 466 | bool boot = false; | ||
| 467 | int ret; | ||
| 468 | |||
| 469 | if (vga_switcheroo_client_probe_defer(pdev)) | ||
| 470 | return -EPROBE_DEFER; | ||
| 471 | |||
| 472 | /* We need to check that the chipset is supported before booting | ||
| 473 | * fbdev off the hardware, as there's no way to put it back. | ||
| 474 | */ | ||
| 475 | ret = nvkm_device_pci_new(pdev, NULL, "error", true, false, 0, &device); | ||
| 476 | if (ret) | ||
| 477 | return ret; | ||
| 478 | |||
| 479 | nvkm_device_del(&device); | ||
| 480 | |||
| 481 | /* Remove conflicting drivers (vesafb, efifb etc). */ | ||
| 482 | aper = alloc_apertures(3); | ||
| 483 | if (!aper) | ||
| 484 | return -ENOMEM; | ||
| 485 | |||
| 486 | aper->ranges[0].base = pci_resource_start(pdev, 1); | ||
| 487 | aper->ranges[0].size = pci_resource_len(pdev, 1); | ||
| 488 | aper->count = 1; | ||
| 489 | |||
| 490 | if (pci_resource_len(pdev, 2)) { | ||
| 491 | aper->ranges[aper->count].base = pci_resource_start(pdev, 2); | ||
| 492 | aper->ranges[aper->count].size = pci_resource_len(pdev, 2); | ||
| 493 | aper->count++; | ||
| 494 | } | ||
| 495 | |||
| 496 | if (pci_resource_len(pdev, 3)) { | ||
| 497 | aper->ranges[aper->count].base = pci_resource_start(pdev, 3); | ||
| 498 | aper->ranges[aper->count].size = pci_resource_len(pdev, 3); | ||
| 499 | aper->count++; | ||
| 500 | } | ||
| 501 | |||
| 502 | #ifdef CONFIG_X86 | ||
| 503 | boot = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; | ||
| 504 | #endif | ||
| 505 | if (nouveau_modeset != 2) | ||
| 506 | drm_fb_helper_remove_conflicting_framebuffers(aper, "nouveaufb", boot); | ||
| 507 | kfree(aper); | ||
| 508 | |||
| 509 | ret = nvkm_device_pci_new(pdev, nouveau_config, nouveau_debug, | ||
| 510 | true, true, ~0ULL, &device); | ||
| 511 | if (ret) | ||
| 512 | return ret; | ||
| 513 | |||
| 514 | pci_set_master(pdev); | ||
| 515 | |||
| 516 | if (nouveau_atomic) | ||
| 517 | driver_pci.driver_features |= DRIVER_ATOMIC; | ||
| 518 | |||
| 519 | ret = drm_get_pci_dev(pdev, pent, &driver_pci); | ||
| 520 | if (ret) { | ||
| 521 | nvkm_device_del(&device); | ||
| 522 | return ret; | ||
| 523 | } | ||
| 524 | |||
| 525 | return 0; | ||
| 526 | } | ||
| 527 | |||
| 528 | static int | 461 | static int |
| 529 | nouveau_drm_load(struct drm_device *dev, unsigned long flags) | 462 | nouveau_drm_device_init(struct drm_device *dev) |
| 530 | { | 463 | { |
| 531 | struct nouveau_drm *drm; | 464 | struct nouveau_drm *drm; |
| 532 | int ret; | 465 | int ret; |
| @@ -538,11 +471,11 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) | |||
| 538 | 471 | ||
| 539 | ret = nouveau_cli_init(drm, "DRM-master", &drm->master); | 472 | ret = nouveau_cli_init(drm, "DRM-master", &drm->master); |
| 540 | if (ret) | 473 | if (ret) |
| 541 | return ret; | 474 | goto fail_alloc; |
| 542 | 475 | ||
| 543 | ret = nouveau_cli_init(drm, "DRM", &drm->client); | 476 | ret = nouveau_cli_init(drm, "DRM", &drm->client); |
| 544 | if (ret) | 477 | if (ret) |
| 545 | return ret; | 478 | goto fail_master; |
| 546 | 479 | ||
| 547 | dev->irq_enabled = true; | 480 | dev->irq_enabled = true; |
| 548 | 481 | ||
| @@ -605,13 +538,15 @@ fail_bios: | |||
| 605 | fail_ttm: | 538 | fail_ttm: |
| 606 | nouveau_vga_fini(drm); | 539 | nouveau_vga_fini(drm); |
| 607 | nouveau_cli_fini(&drm->client); | 540 | nouveau_cli_fini(&drm->client); |
| 541 | fail_master: | ||
| 608 | nouveau_cli_fini(&drm->master); | 542 | nouveau_cli_fini(&drm->master); |
| 543 | fail_alloc: | ||
| 609 | kfree(drm); | 544 | kfree(drm); |
| 610 | return ret; | 545 | return ret; |
| 611 | } | 546 | } |
| 612 | 547 | ||
| 613 | static void | 548 | static void |
| 614 | nouveau_drm_unload(struct drm_device *dev) | 549 | nouveau_drm_device_fini(struct drm_device *dev) |
| 615 | { | 550 | { |
| 616 | struct nouveau_drm *drm = nouveau_drm(dev); | 551 | struct nouveau_drm *drm = nouveau_drm(dev); |
| 617 | 552 | ||
| @@ -640,18 +575,116 @@ nouveau_drm_unload(struct drm_device *dev) | |||
| 640 | kfree(drm); | 575 | kfree(drm); |
| 641 | } | 576 | } |
| 642 | 577 | ||
| 578 | static int nouveau_drm_probe(struct pci_dev *pdev, | ||
| 579 | const struct pci_device_id *pent) | ||
| 580 | { | ||
| 581 | struct nvkm_device *device; | ||
| 582 | struct drm_device *drm_dev; | ||
| 583 | struct apertures_struct *aper; | ||
| 584 | bool boot = false; | ||
| 585 | int ret; | ||
| 586 | |||
| 587 | if (vga_switcheroo_client_probe_defer(pdev)) | ||
| 588 | return -EPROBE_DEFER; | ||
| 589 | |||
| 590 | /* We need to check that the chipset is supported before booting | ||
| 591 | * fbdev off the hardware, as there's no way to put it back. | ||
| 592 | */ | ||
| 593 | ret = nvkm_device_pci_new(pdev, NULL, "error", true, false, 0, &device); | ||
| 594 | if (ret) | ||
| 595 | return ret; | ||
| 596 | |||
| 597 | nvkm_device_del(&device); | ||
| 598 | |||
| 599 | /* Remove conflicting drivers (vesafb, efifb etc). */ | ||
| 600 | aper = alloc_apertures(3); | ||
| 601 | if (!aper) | ||
| 602 | return -ENOMEM; | ||
| 603 | |||
| 604 | aper->ranges[0].base = pci_resource_start(pdev, 1); | ||
| 605 | aper->ranges[0].size = pci_resource_len(pdev, 1); | ||
| 606 | aper->count = 1; | ||
| 607 | |||
| 608 | if (pci_resource_len(pdev, 2)) { | ||
| 609 | aper->ranges[aper->count].base = pci_resource_start(pdev, 2); | ||
| 610 | aper->ranges[aper->count].size = pci_resource_len(pdev, 2); | ||
| 611 | aper->count++; | ||
| 612 | } | ||
| 613 | |||
| 614 | if (pci_resource_len(pdev, 3)) { | ||
| 615 | aper->ranges[aper->count].base = pci_resource_start(pdev, 3); | ||
| 616 | aper->ranges[aper->count].size = pci_resource_len(pdev, 3); | ||
| 617 | aper->count++; | ||
| 618 | } | ||
| 619 | |||
| 620 | #ifdef CONFIG_X86 | ||
| 621 | boot = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; | ||
| 622 | #endif | ||
| 623 | if (nouveau_modeset != 2) | ||
| 624 | drm_fb_helper_remove_conflicting_framebuffers(aper, "nouveaufb", boot); | ||
| 625 | kfree(aper); | ||
| 626 | |||
| 627 | ret = nvkm_device_pci_new(pdev, nouveau_config, nouveau_debug, | ||
| 628 | true, true, ~0ULL, &device); | ||
| 629 | if (ret) | ||
| 630 | return ret; | ||
| 631 | |||
| 632 | pci_set_master(pdev); | ||
| 633 | |||
| 634 | if (nouveau_atomic) | ||
| 635 | driver_pci.driver_features |= DRIVER_ATOMIC; | ||
| 636 | |||
| 637 | drm_dev = drm_dev_alloc(&driver_pci, &pdev->dev); | ||
| 638 | if (IS_ERR(drm_dev)) { | ||
| 639 | ret = PTR_ERR(drm_dev); | ||
| 640 | goto fail_nvkm; | ||
| 641 | } | ||
| 642 | |||
| 643 | ret = pci_enable_device(pdev); | ||
| 644 | if (ret) | ||
| 645 | goto fail_drm; | ||
| 646 | |||
| 647 | drm_dev->pdev = pdev; | ||
| 648 | pci_set_drvdata(pdev, drm_dev); | ||
| 649 | |||
| 650 | ret = nouveau_drm_device_init(drm_dev); | ||
| 651 | if (ret) | ||
| 652 | goto fail_pci; | ||
| 653 | |||
| 654 | ret = drm_dev_register(drm_dev, pent->driver_data); | ||
| 655 | if (ret) | ||
| 656 | goto fail_drm_dev_init; | ||
| 657 | |||
| 658 | return 0; | ||
| 659 | |||
| 660 | fail_drm_dev_init: | ||
| 661 | nouveau_drm_device_fini(drm_dev); | ||
| 662 | fail_pci: | ||
| 663 | pci_disable_device(pdev); | ||
| 664 | fail_drm: | ||
| 665 | drm_dev_put(drm_dev); | ||
| 666 | fail_nvkm: | ||
| 667 | nvkm_device_del(&device); | ||
| 668 | return ret; | ||
| 669 | } | ||
| 670 | |||
| 643 | void | 671 | void |
| 644 | nouveau_drm_device_remove(struct drm_device *dev) | 672 | nouveau_drm_device_remove(struct drm_device *dev) |
| 645 | { | 673 | { |
| 674 | struct pci_dev *pdev = dev->pdev; | ||
| 646 | struct nouveau_drm *drm = nouveau_drm(dev); | 675 | struct nouveau_drm *drm = nouveau_drm(dev); |
| 647 | struct nvkm_client *client; | 676 | struct nvkm_client *client; |
| 648 | struct nvkm_device *device; | 677 | struct nvkm_device *device; |
| 649 | 678 | ||
| 679 | drm_dev_unregister(dev); | ||
| 680 | |||
| 650 | dev->irq_enabled = false; | 681 | dev->irq_enabled = false; |
| 651 | client = nvxx_client(&drm->client.base); | 682 | client = nvxx_client(&drm->client.base); |
| 652 | device = nvkm_device_find(client->device); | 683 | device = nvkm_device_find(client->device); |
| 653 | drm_put_dev(dev); | ||
| 654 | 684 | ||
| 685 | nouveau_drm_device_fini(dev); | ||
| 686 | pci_disable_device(pdev); | ||
| 687 | drm_dev_put(dev); | ||
| 655 | nvkm_device_del(&device); | 688 | nvkm_device_del(&device); |
| 656 | } | 689 | } |
| 657 | 690 | ||
| @@ -1018,8 +1051,6 @@ driver_stub = { | |||
| 1018 | DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER | | 1051 | DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER | |
| 1019 | DRIVER_KMS_LEGACY_CONTEXT, | 1052 | DRIVER_KMS_LEGACY_CONTEXT, |
| 1020 | 1053 | ||
| 1021 | .load = nouveau_drm_load, | ||
| 1022 | .unload = nouveau_drm_unload, | ||
| 1023 | .open = nouveau_drm_open, | 1054 | .open = nouveau_drm_open, |
| 1024 | .postclose = nouveau_drm_postclose, | 1055 | .postclose = nouveau_drm_postclose, |
| 1025 | .lastclose = nouveau_vga_lastclose, | 1056 | .lastclose = nouveau_vga_lastclose, |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 6e1acaec3400..0b2191fa96f7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h | |||
| @@ -194,8 +194,6 @@ struct nouveau_drm { | |||
| 194 | /* modesetting */ | 194 | /* modesetting */ |
| 195 | struct nvbios vbios; | 195 | struct nvbios vbios; |
| 196 | struct nouveau_display *display; | 196 | struct nouveau_display *display; |
| 197 | struct backlight_device *backlight; | ||
| 198 | struct list_head bl_connectors; | ||
| 199 | struct work_struct hpd_work; | 197 | struct work_struct hpd_work; |
| 200 | struct work_struct fbcon_work; | 198 | struct work_struct fbcon_work; |
| 201 | int fbcon_new_state; | 199 | int fbcon_new_state; |
| @@ -244,10 +242,12 @@ void nouveau_drm_device_remove(struct drm_device *dev); | |||
| 244 | struct nouveau_cli *_cli = (c); \ | 242 | struct nouveau_cli *_cli = (c); \ |
| 245 | dev_##l(_cli->drm->dev->dev, "%s: "f, _cli->name, ##a); \ | 243 | dev_##l(_cli->drm->dev->dev, "%s: "f, _cli->name, ##a); \ |
| 246 | } while(0) | 244 | } while(0) |
| 245 | |||
| 247 | #define NV_FATAL(drm,f,a...) NV_PRINTK(crit, &(drm)->client, f, ##a) | 246 | #define NV_FATAL(drm,f,a...) NV_PRINTK(crit, &(drm)->client, f, ##a) |
| 248 | #define NV_ERROR(drm,f,a...) NV_PRINTK(err, &(drm)->client, f, ##a) | 247 | #define NV_ERROR(drm,f,a...) NV_PRINTK(err, &(drm)->client, f, ##a) |
| 249 | #define NV_WARN(drm,f,a...) NV_PRINTK(warn, &(drm)->client, f, ##a) | 248 | #define NV_WARN(drm,f,a...) NV_PRINTK(warn, &(drm)->client, f, ##a) |
| 250 | #define NV_INFO(drm,f,a...) NV_PRINTK(info, &(drm)->client, f, ##a) | 249 | #define NV_INFO(drm,f,a...) NV_PRINTK(info, &(drm)->client, f, ##a) |
| 250 | |||
| 251 | #define NV_DEBUG(drm,f,a...) do { \ | 251 | #define NV_DEBUG(drm,f,a...) do { \ |
| 252 | if (unlikely(drm_debug & DRM_UT_DRIVER)) \ | 252 | if (unlikely(drm_debug & DRM_UT_DRIVER)) \ |
| 253 | NV_PRINTK(info, &(drm)->client, f, ##a); \ | 253 | NV_PRINTK(info, &(drm)->client, f, ##a); \ |
| @@ -257,6 +257,12 @@ void nouveau_drm_device_remove(struct drm_device *dev); | |||
| 257 | NV_PRINTK(info, &(drm)->client, f, ##a); \ | 257 | NV_PRINTK(info, &(drm)->client, f, ##a); \ |
| 258 | } while(0) | 258 | } while(0) |
| 259 | 259 | ||
| 260 | #define NV_PRINTK_ONCE(l,c,f,a...) NV_PRINTK(l##_once,c,f, ##a) | ||
| 261 | |||
| 262 | #define NV_ERROR_ONCE(drm,f,a...) NV_PRINTK_ONCE(err, &(drm)->client, f, ##a) | ||
| 263 | #define NV_WARN_ONCE(drm,f,a...) NV_PRINTK_ONCE(warn, &(drm)->client, f, ##a) | ||
| 264 | #define NV_INFO_ONCE(drm,f,a...) NV_PRINTK_ONCE(info, &(drm)->client, f, ##a) | ||
| 265 | |||
| 260 | extern int nouveau_modeset; | 266 | extern int nouveau_modeset; |
| 261 | 267 | ||
| 262 | #endif | 268 | #endif |
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild index 3d485dbf310a..8089ac9a12e2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild | |||
| @@ -50,6 +50,7 @@ nvkm-y += nvkm/engine/disp/hdmig84.o | |||
| 50 | nvkm-y += nvkm/engine/disp/hdmigt215.o | 50 | nvkm-y += nvkm/engine/disp/hdmigt215.o |
| 51 | nvkm-y += nvkm/engine/disp/hdmigf119.o | 51 | nvkm-y += nvkm/engine/disp/hdmigf119.o |
| 52 | nvkm-y += nvkm/engine/disp/hdmigk104.o | 52 | nvkm-y += nvkm/engine/disp/hdmigk104.o |
| 53 | nvkm-y += nvkm/engine/disp/hdmigm200.o | ||
| 53 | nvkm-y += nvkm/engine/disp/hdmigv100.o | 54 | nvkm-y += nvkm/engine/disp/hdmigv100.o |
| 54 | 55 | ||
| 55 | nvkm-y += nvkm/engine/disp/conn.o | 56 | nvkm-y += nvkm/engine/disp/conn.o |
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigm200.c new file mode 100644 index 000000000000..9b16a08eb4d9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigm200.c | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2018 Ilia Mirkin | ||
| 3 | * | ||
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 5 | * copy of this software and associated documentation files (the "Software"), | ||
| 6 | * to deal in the Software without restriction, including without limitation | ||
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 9 | * Software is furnished to do so, subject to the following conditions: | ||
| 10 | * | ||
| 11 | * The above copyright notice and this permission notice shall be included in | ||
| 12 | * all copies or substantial portions of the Software. | ||
| 13 | * | ||
| 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
| 18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
| 19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
| 20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
| 21 | * | ||
| 22 | * Authors: Ilia Mirkin | ||
| 23 | */ | ||
| 24 | #include "hdmi.h" | ||
| 25 | |||
| 26 | void | ||
| 27 | gm200_hdmi_scdc(struct nvkm_ior *ior, int head, u8 scdc) | ||
| 28 | { | ||
| 29 | struct nvkm_device *device = ior->disp->engine.subdev.device; | ||
| 30 | const u32 hoff = head * 0x800; | ||
| 31 | const u32 ctrl = scdc & 0x3; | ||
| 32 | |||
| 33 | nvkm_mask(device, 0x61c5bc + hoff, 0x00000003, ctrl); | ||
| 34 | |||
| 35 | ior->tmds.high_speed = !!(scdc & 0x2); | ||
| 36 | } | ||
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index 19911211a12a..0f0c86c32ec3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h | |||
| @@ -41,6 +41,11 @@ struct nvkm_ior { | |||
| 41 | u8 nr; | 41 | u8 nr; |
| 42 | u8 bw; | 42 | u8 bw; |
| 43 | } dp; | 43 | } dp; |
| 44 | |||
| 45 | /* Armed TMDS state. */ | ||
| 46 | struct { | ||
| 47 | bool high_speed; | ||
| 48 | } tmds; | ||
| 44 | }; | 49 | }; |
| 45 | 50 | ||
| 46 | struct nvkm_ior_func { | 51 | struct nvkm_ior_func { |
| @@ -61,6 +66,7 @@ struct nvkm_ior_func { | |||
| 61 | void (*ctrl)(struct nvkm_ior *, int head, bool enable, | 66 | void (*ctrl)(struct nvkm_ior *, int head, bool enable, |
| 62 | u8 max_ac_packet, u8 rekey, u8 *avi, u8 avi_size, | 67 | u8 max_ac_packet, u8 rekey, u8 *avi, u8 avi_size, |
| 63 | u8 *vendor, u8 vendor_size); | 68 | u8 *vendor, u8 vendor_size); |
| 69 | void (*scdc)(struct nvkm_ior *, int head, u8 scdc); | ||
| 64 | } hdmi; | 70 | } hdmi; |
| 65 | 71 | ||
| 66 | struct { | 72 | struct { |
| @@ -144,6 +150,8 @@ void gf119_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); | |||
| 144 | void gk104_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); | 150 | void gk104_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); |
| 145 | void gv100_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); | 151 | void gv100_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); |
| 146 | 152 | ||
| 153 | void gm200_hdmi_scdc(struct nvkm_ior *, int, u8); | ||
| 154 | |||
| 147 | void gt215_hda_hpd(struct nvkm_ior *, int, bool); | 155 | void gt215_hda_hpd(struct nvkm_ior *, int, bool); |
| 148 | void gt215_hda_eld(struct nvkm_ior *, u8 *, u8); | 156 | void gt215_hda_eld(struct nvkm_ior *, u8 *, u8); |
| 149 | 157 | ||
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index 3aa5a2879239..5f758948d6e1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c | |||
| @@ -176,9 +176,10 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) | |||
| 176 | nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); | 176 | nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); |
| 177 | if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { | 177 | if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { |
| 178 | nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " | 178 | nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " |
| 179 | "max_ac_packet %d rekey %d\n", | 179 | "max_ac_packet %d rekey %d scdc %d\n", |
| 180 | args->v0.version, args->v0.state, | 180 | args->v0.version, args->v0.state, |
| 181 | args->v0.max_ac_packet, args->v0.rekey); | 181 | args->v0.max_ac_packet, args->v0.rekey, |
| 182 | args->v0.scdc); | ||
| 182 | if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) | 183 | if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) |
| 183 | return -EINVAL; | 184 | return -EINVAL; |
| 184 | if ((args->v0.avi_infoframe_length | 185 | if ((args->v0.avi_infoframe_length |
| @@ -202,6 +203,11 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) | |||
| 202 | args->v0.max_ac_packet, | 203 | args->v0.max_ac_packet, |
| 203 | args->v0.rekey, avi, avi_size, | 204 | args->v0.rekey, avi, avi_size, |
| 204 | vendor, vendor_size); | 205 | vendor, vendor_size); |
| 206 | |||
| 207 | if (outp->ior->func->hdmi.scdc) | ||
| 208 | outp->ior->func->hdmi.scdc( | ||
| 209 | outp->ior, hidx, args->v0.scdc); | ||
| 210 | |||
| 205 | return 0; | 211 | return 0; |
| 206 | } | 212 | } |
| 207 | break; | 213 | break; |
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index e6e6dfbb1283..456a5a143522 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c | |||
| @@ -120,13 +120,16 @@ void | |||
| 120 | gf119_sor_clock(struct nvkm_ior *sor) | 120 | gf119_sor_clock(struct nvkm_ior *sor) |
| 121 | { | 121 | { |
| 122 | struct nvkm_device *device = sor->disp->engine.subdev.device; | 122 | struct nvkm_device *device = sor->disp->engine.subdev.device; |
| 123 | const int div = sor->asy.link == 3; | ||
| 124 | const u32 soff = nv50_ior_base(sor); | 123 | const u32 soff = nv50_ior_base(sor); |
| 124 | u32 div1 = sor->asy.link == 3; | ||
| 125 | u32 div2 = sor->asy.link == 3; | ||
| 125 | if (sor->asy.proto == TMDS) { | 126 | if (sor->asy.proto == TMDS) { |
| 126 | /* NFI why, but this sets DP_LINK_BW_2_7 when using TMDS. */ | 127 | const u32 speed = sor->tmds.high_speed ? 0x14 : 0x0a; |
| 127 | nvkm_mask(device, 0x612300 + soff, 0x007c0000, 0x0a << 18); | 128 | nvkm_mask(device, 0x612300 + soff, 0x007c0000, speed << 18); |
| 129 | if (sor->tmds.high_speed) | ||
| 130 | div2 = 1; | ||
| 128 | } | 131 | } |
| 129 | nvkm_mask(device, 0x612300 + soff, 0x00000707, (div << 8) | div); | 132 | nvkm_mask(device, 0x612300 + soff, 0x00000707, (div2 << 8) | div1); |
| 130 | } | 133 | } |
| 131 | 134 | ||
| 132 | void | 135 | void |
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index d892bdf04034..384f82652bec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c | |||
| @@ -99,6 +99,7 @@ gm200_sor = { | |||
| 99 | .clock = gf119_sor_clock, | 99 | .clock = gf119_sor_clock, |
| 100 | .hdmi = { | 100 | .hdmi = { |
| 101 | .ctrl = gk104_hdmi_ctrl, | 101 | .ctrl = gk104_hdmi_ctrl, |
| 102 | .scdc = gm200_hdmi_scdc, | ||
| 102 | }, | 103 | }, |
| 103 | .dp = { | 104 | .dp = { |
| 104 | .lanes = { 0, 1, 2, 3 }, | 105 | .lanes = { 0, 1, 2, 3 }, |
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgv100.c index 040db8a338de..8ba881a729ee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgv100.c | |||
| @@ -88,6 +88,7 @@ gv100_sor = { | |||
| 88 | .clock = gf119_sor_clock, | 88 | .clock = gf119_sor_clock, |
| 89 | .hdmi = { | 89 | .hdmi = { |
| 90 | .ctrl = gv100_hdmi_ctrl, | 90 | .ctrl = gv100_hdmi_ctrl, |
| 91 | .scdc = gm200_hdmi_scdc, | ||
| 91 | }, | 92 | }, |
| 92 | .dp = { | 93 | .dp = { |
| 93 | .lanes = { 0, 1, 2, 3 }, | 94 | .lanes = { 0, 1, 2, 3 }, |
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c index d02e183717dc..5c14d6ac855d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c | |||
| @@ -801,6 +801,7 @@ acr_r352_load(struct nvkm_acr *_acr, struct nvkm_falcon *falcon, | |||
| 801 | bl = acr->hsbl_unload_blob; | 801 | bl = acr->hsbl_unload_blob; |
| 802 | } else { | 802 | } else { |
| 803 | nvkm_error(_acr->subdev, "invalid secure boot blob!\n"); | 803 | nvkm_error(_acr->subdev, "invalid secure boot blob!\n"); |
| 804 | kfree(bl_desc); | ||
| 804 | return -EINVAL; | 805 | return -EINVAL; |
| 805 | } | 806 | } |
| 806 | 807 | ||
