From 1c30cd09e37e0804f604f3932c695da13e9d442f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 8 Nov 2012 14:22:28 +1000 Subject: [PATCH] drm/nvd0/disp: move HDMI control to core Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/Makefile | 1 + .../drm/nouveau/core/engine/disp/hdminvd0.c | 62 +++++++++++++++++++ .../gpu/drm/nouveau/core/engine/disp/nv50.h | 3 + .../gpu/drm/nouveau/core/engine/disp/nva3.c | 1 + .../gpu/drm/nouveau/core/engine/disp/nvd0.c | 1 + .../gpu/drm/nouveau/core/engine/disp/nve0.c | 1 + .../drm/nouveau/core/engine/disp/sornv50.c | 3 + .../gpu/drm/nouveau/core/include/core/class.h | 6 ++ drivers/gpu/drm/nouveau/nvd0_display.c | 37 +++-------- 9 files changed, 86 insertions(+), 29 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index ac9d9281609e..01132dd09109 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -139,6 +139,7 @@ nouveau-y += core/engine/disp/nvd0.o nouveau-y += core/engine/disp/nve0.o nouveau-y += core/engine/disp/dacnv50.o nouveau-y += core/engine/disp/hdanvd0.o +nouveau-y += core/engine/disp/hdminvd0.o nouveau-y += core/engine/disp/sornv50.o nouveau-y += core/engine/disp/sornvd0.o nouveau-y += core/engine/disp/vga.o diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c new file mode 100644 index 000000000000..5151bb261832 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c @@ -0,0 +1,62 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include +#include + +#include "nv50.h" + +int +nvd0_hdmi_ctrl(struct nv50_disp_priv *priv, int head, int or, u32 data) +{ + const u32 hoff = (head * 0x800); + + if (!(data & NV84_DISP_SOR_HDMI_PWR_STATE_ON)) { + nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000); + nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000); + nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000); + return 0; + } + + /* AVI InfoFrame */ + nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000); + nv_wr32(priv, 0x61671c + hoff, 0x000d0282); + nv_wr32(priv, 0x616720 + hoff, 0x0000006f); + nv_wr32(priv, 0x616724 + hoff, 0x00000000); + nv_wr32(priv, 0x616728 + hoff, 0x00000000); + nv_wr32(priv, 0x61672c + hoff, 0x00000000); + nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000001); + + /* ??? InfoFrame? */ + nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000); + nv_wr32(priv, 0x6167ac + hoff, 0x00000010); + nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000001); + + /* HDMI_CTRL */ + nv_mask(priv, 0x616798 + hoff, 0x401f007f, data); + + /* NFI, audio doesn't work without it though.. */ + nv_mask(priv, 0x616548 + hoff, 0x00000070, 0x00000000); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h index 78934c54d22c..48e3f0d58cbf 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h @@ -25,6 +25,7 @@ struct nv50_disp_priv { int nr; int (*power)(struct nv50_disp_priv *, int sor, u32 data); int (*hda_eld)(struct nv50_disp_priv *, int sor, u8 *, u32); + int (*hdmi)(struct nv50_disp_priv *, int head, int sor, u32); int (*dp_train)(struct nv50_disp_priv *, int sor, int link, u16 type, u16 mask, u32 data, struct dcb_output *); @@ -52,6 +53,8 @@ int nv50_sor_power(struct nv50_disp_priv *, int, u32); int nvd0_hda_eld(struct nv50_disp_priv *, int, u8 *, u32); +int nvd0_hdmi_ctrl(struct nv50_disp_priv *, int, int, u32); + int nvd0_sor_dp_train(struct nv50_disp_priv *, int, int, u16, u16, u32, struct dcb_output *); int nvd0_sor_dp_lnkctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32, diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c index ced4c81fee16..b557108b2f36 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c @@ -43,6 +43,7 @@ struct nouveau_omthds nva3_disp_base_omthds[] = { { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd }, + { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, { SOR_MTHD(NV94_DISP_SOR_DP_TRAIN) , nv50_sor_mthd }, { SOR_MTHD(NV94_DISP_SOR_DP_LNKCTL) , nv50_sor_mthd }, { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(0)), nv50_sor_mthd }, diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c index cc2c3a4c31aa..8589b953b284 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c @@ -900,6 +900,7 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->dac.sense = nv50_dac_sense; priv->sor.power = nv50_sor_power; priv->sor.hda_eld = nvd0_hda_eld; + priv->sor.hdmi = nvd0_hdmi_ctrl; priv->sor.dp_train = nvd0_sor_dp_train; priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl; priv->sor.dp_drvctl = nvd0_sor_dp_drvctl; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c index 4a7ebe496dec..9b83a70091f9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c @@ -70,6 +70,7 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->dac.sense = nv50_dac_sense; priv->sor.power = nv50_sor_power; priv->sor.hda_eld = nvd0_hda_eld; + priv->sor.hdmi = nvd0_hdmi_ctrl; priv->sor.dp_train = nvd0_sor_dp_train; priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl; priv->sor.dp_drvctl = nvd0_sor_dp_drvctl; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c index 21d7761a5566..4a8117d33f5a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c @@ -91,6 +91,9 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) case NVA3_DISP_SOR_HDA_ELD: ret = priv->sor.hda_eld(priv, or, args, size); break; + case NV84_DISP_SOR_HDMI_PWR: + ret = priv->sor.hdmi(priv, head, or, data); + break; case NV94_DISP_SOR_DP_TRAIN: ret = priv->sor.dp_train(priv, or, link, type, mask, data, &outp); break; diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h index cc725945dabe..de3ce108221e 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/class.h +++ b/drivers/gpu/drm/nouveau/core/include/core/class.h @@ -182,6 +182,12 @@ struct nve0_channel_ind_class { #define NV50_DISP_SOR_PWR_STATE_ON 0x00000001 #define NV50_DISP_SOR_PWR_STATE_OFF 0x00000000 #define NVA3_DISP_SOR_HDA_ELD 0x00010100 +#define NV84_DISP_SOR_HDMI_PWR 0x00012000 +#define NV84_DISP_SOR_HDMI_PWR_STATE 0x40000000 +#define NV84_DISP_SOR_HDMI_PWR_STATE_OFF 0x00000000 +#define NV84_DISP_SOR_HDMI_PWR_STATE_ON 0x40000000 +#define NV84_DISP_SOR_HDMI_PWR_MAX_AC_PACKET 0x001f0000 +#define NV84_DISP_SOR_HDMI_PWR_REKEY 0x0000007f #define NV94_DISP_SOR_DP_TRAIN 0x00016000 #define NV94_DISP_SOR_DP_TRAIN_PATTERN 0x00000003 #define NV94_DISP_SOR_DP_TRAIN_PATTERN_DISABLED 0x00000000 diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c index 0620b786d7bf..9acf4a0c5d9a 100644 --- a/drivers/gpu/drm/nouveau/nvd0_display.c +++ b/drivers/gpu/drm/nouveau/nvd0_display.c @@ -1269,9 +1269,8 @@ nvd0_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode) struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); struct nouveau_connector *nv_connector; - struct drm_device *dev = encoder->dev; - struct nouveau_device *device = nouveau_dev(dev); - int head = nv_crtc->index * 0x800; + struct nvd0_disp *disp = nvd0_disp(encoder->dev); + const u32 moff = (nv_crtc->index << 3) | nv_encoder->or; u32 rekey = 56; /* binary driver, and tegra constant */ u32 max_ac_packet; @@ -1284,26 +1283,9 @@ nvd0_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode) max_ac_packet -= 18; /* constant from tegra */ max_ac_packet /= 32; - /* AVI InfoFrame */ - nv_mask(device, 0x616714 + head, 0x00000001, 0x00000000); - nv_wr32(device, 0x61671c + head, 0x000d0282); - nv_wr32(device, 0x616720 + head, 0x0000006f); - nv_wr32(device, 0x616724 + head, 0x00000000); - nv_wr32(device, 0x616728 + head, 0x00000000); - nv_wr32(device, 0x61672c + head, 0x00000000); - nv_mask(device, 0x616714 + head, 0x00000001, 0x00000001); - - /* ??? InfoFrame? */ - nv_mask(device, 0x6167a4 + head, 0x00000001, 0x00000000); - nv_wr32(device, 0x6167ac + head, 0x00000010); - nv_mask(device, 0x6167a4 + head, 0x00000001, 0x00000001); - - /* HDMI_CTRL */ - nv_mask(device, 0x616798 + head, 0x401f007f, 0x40000000 | rekey | - max_ac_packet << 16); - - /* NFI, audio doesn't work without it though.. */ - nv_mask(device, 0x616548 + head, 0x00000070, 0x00000000); + nv_call(disp->core, NV84_DISP_SOR_HDMI_PWR + moff, + NV84_DISP_SOR_HDMI_PWR_STATE_ON | + (max_ac_packet << 16) | rekey); nvd0_audio_mode_set(encoder, mode); } @@ -1313,15 +1295,12 @@ nvd0_hdmi_disconnect(struct drm_encoder *encoder) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc); - struct drm_device *dev = encoder->dev; - struct nouveau_device *device = nouveau_dev(dev); - int head = nv_crtc->index * 0x800; + struct nvd0_disp *disp = nvd0_disp(encoder->dev); + const u32 moff = (nv_crtc->index << 3) | nv_encoder->or; nvd0_audio_disconnect(encoder); - nv_mask(device, 0x616798 + head, 0x40000000, 0x00000000); - nv_mask(device, 0x6167a4 + head, 0x00000001, 0x00000000); - nv_mask(device, 0x616714 + head, 0x00000001, 0x00000000); + nv_call(disp->core, NV84_DISP_SOR_HDMI_PWR + moff, 0x00000000); } /******************************************************************************