diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 0eb4c2d5f92e..306e209d0bee 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -137,6 +137,7 @@ nouveau-y += core/engine/disp/nva0.o nouveau-y += core/engine/disp/nva3.o 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/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/dacnv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c new file mode 100644 index 000000000000..18ba339c1625 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c @@ -0,0 +1,88 @@ +/* + * 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 +#include +#include + +#include "nv50.h" + +int +nv50_dac_power(struct nv50_disp_priv *priv, int or, u32 data) +{ + const u32 stat = (data & NV50_DISP_DAC_PWR_HSYNC) | + (data & NV50_DISP_DAC_PWR_VSYNC) | + (data & NV50_DISP_DAC_PWR_DATA) | + (data & NV50_DISP_DAC_PWR_STATE); + const u32 doff = (or * 0x800); + nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); + nv_mask(priv, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat); + nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); + return 0; +} + +int +nv50_dac_sense(struct nv50_disp_priv *priv, int or) +{ + const u32 doff = (or * 0x800); + int load = -EINVAL; + nv_wr32(priv, 0x61a00c + doff, 0x00100000); + udelay(9500); + nv_wr32(priv, 0x61a00c + doff, 0x80000000); + load = (nv_rd32(priv, 0x61a00c + doff) & 0x38000000) >> 27; + nv_wr32(priv, 0x61a00c + doff, 0x00000000); + return load; +} + +int +nv50_dac_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) +{ + struct nv50_disp_priv *priv = (void *)object->engine; + const u8 or = (mthd & NV50_DISP_DAC_MTHD_OR); + u32 *data = args; + int ret; + + if (size < sizeof(u32)) + return -EINVAL; + + switch (mthd & ~0x3f) { + case NV50_DISP_DAC_PWR: + ret = priv->dac.power(priv, or, data[0]); + break; + case NV50_DISP_DAC_LOAD: + ret = priv->dac.sense(priv, or); + if (ret >= 0) { + data[0] = ret; + ret = 0; + } + break; + default: + BUG_ON(1); + } + + return ret; +} diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h index ce490a148ece..b5e95fecafaa 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h @@ -18,6 +18,8 @@ struct nv50_disp_priv { } head; struct { int nr; + int (*power)(struct nv50_disp_priv *, int dac, u32 data); + int (*sense)(struct nv50_disp_priv *, int dac); } dac; struct { int nr; @@ -36,6 +38,12 @@ struct nv50_disp_priv { extern struct nouveau_omthds nva3_disp_base_omthds[]; +#define DAC_MTHD(n) (n), (n) + 0x03 + +int nv50_dac_mthd(struct nouveau_object *, u32, void *, u32); +int nv50_dac_power(struct nv50_disp_priv *, int, u32); +int nv50_dac_sense(struct nv50_disp_priv *, int); + #define SOR_MTHD(n) (n), (n) + 0x3f int nv50_sor_mthd(struct nouveau_object *, u32, void *, u32); diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c index f1d8e5a65591..6b687ef06d2e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c @@ -48,6 +48,8 @@ nva3_disp_base_omthds[] = { { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(1)), nv50_sor_mthd }, { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(2)), nv50_sor_mthd }, { SOR_MTHD(NV94_DISP_SOR_DP_DRVCTL(3)), nv50_sor_mthd }, + { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, + { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, {}, }; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c index 29f65dcdc1a9..63611b898ea4 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c @@ -896,6 +896,8 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->head.nr = nv_rd32(priv, 0x022448); priv->dac.nr = 3; priv->sor.nr = 4; + priv->dac.power = nv50_dac_power; + priv->dac.sense = nv50_dac_sense; priv->sor.power = nv50_sor_power; priv->sor.dp_train = nvd0_sor_dp_train; priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c index 6c21929d8e24..b2b0f3c83b3d 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c @@ -66,6 +66,8 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->head.nr = nv_rd32(priv, 0x022448); priv->dac.nr = 3; priv->sor.nr = 4; + priv->dac.power = nv50_dac_power; + priv->dac.sense = nv50_dac_sense; priv->sor.power = nv50_sor_power; priv->sor.dp_train = nvd0_sor_dp_train; priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl; diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h index 7c95ca6a44cc..221d48bc8c83 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/class.h +++ b/drivers/gpu/drm/nouveau/core/include/core/class.h @@ -194,6 +194,26 @@ struct nve0_channel_ind_class { #define NV94_DISP_SOR_DP_DRVCTL_VS 0x00000300 #define NV94_DISP_SOR_DP_DRVCTL_PE 0x00000003 +#define NV50_DISP_DAC_MTHD 0x00020000 +#define NV50_DISP_DAC_MTHD_TYPE 0x0000f000 +#define NV50_DISP_DAC_MTHD_OR 0x00000003 + +#define NV50_DISP_DAC_PWR 0x00020000 +#define NV50_DISP_DAC_PWR_HSYNC 0x00000001 +#define NV50_DISP_DAC_PWR_HSYNC_ON 0x00000000 +#define NV50_DISP_DAC_PWR_HSYNC_LO 0x00000001 +#define NV50_DISP_DAC_PWR_VSYNC 0x00000004 +#define NV50_DISP_DAC_PWR_VSYNC_ON 0x00000000 +#define NV50_DISP_DAC_PWR_VSYNC_LO 0x00000004 +#define NV50_DISP_DAC_PWR_DATA 0x00000010 +#define NV50_DISP_DAC_PWR_DATA_ON 0x00000000 +#define NV50_DISP_DAC_PWR_DATA_LO 0x00000010 +#define NV50_DISP_DAC_PWR_STATE 0x00000040 +#define NV50_DISP_DAC_PWR_STATE_ON 0x00000000 +#define NV50_DISP_DAC_PWR_STATE_OFF 0x00000040 +#define NV50_DISP_DAC_LOAD 0x0002000c +#define NV50_DISP_DAC_LOAD_VALUE 0x00000007 + struct nv50_display_class { }; diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c index ea1ae0da71d0..ac12af7057bd 100644 --- a/drivers/gpu/drm/nouveau/nvd0_display.c +++ b/drivers/gpu/drm/nouveau/nvd0_display.c @@ -1076,20 +1076,17 @@ static void nvd0_dac_dpms(struct drm_encoder *encoder, int mode) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct drm_device *dev = encoder->dev; - struct nouveau_device *device = nouveau_dev(dev); + struct nvd0_disp *disp = nvd0_disp(encoder->dev); int or = nv_encoder->or; u32 dpms_ctrl; - dpms_ctrl = 0x80000000; + dpms_ctrl = 0x00000000; if (mode == DRM_MODE_DPMS_STANDBY || mode == DRM_MODE_DPMS_OFF) dpms_ctrl |= 0x00000001; if (mode == DRM_MODE_DPMS_SUSPEND || mode == DRM_MODE_DPMS_OFF) dpms_ctrl |= 0x00000004; - nv_wait(device, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000); - nv_mask(device, 0x61a004 + (or * 0x0800), 0xc000007f, dpms_ctrl); - nv_wait(device, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000); + nv_call(disp->core, NV50_DISP_DAC_PWR + or, dpms_ctrl); } static bool @@ -1177,23 +1174,15 @@ nvd0_dac_disconnect(struct drm_encoder *encoder) static enum drm_connector_status nvd0_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) { - enum drm_connector_status status = connector_status_disconnected; - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct drm_device *dev = encoder->dev; - struct nouveau_device *device = nouveau_dev(dev); - int or = nv_encoder->or; + struct nvd0_disp *disp = nvd0_disp(encoder->dev); + int ret, or = nouveau_encoder(encoder)->or; u32 load; - nv_wr32(device, 0x61a00c + (or * 0x800), 0x00100000); - udelay(9500); - nv_wr32(device, 0x61a00c + (or * 0x800), 0x80000000); + ret = nv_exec(disp->core, NV50_DISP_DAC_LOAD + or, &load, sizeof(load)); + if (ret || load != 7) + return connector_status_disconnected; - load = nv_rd32(device, 0x61a00c + (or * 0x800)); - if ((load & 0x38000000) == 0x38000000) - status = connector_status_connected; - - nv_wr32(device, 0x61a00c + (or * 0x800), 0x00000000); - return status; + return connector_status_connected; } static void