/*
* Copyright 2003 NVIDIA, Corporation
* Copyright 2006 Dave Airlie
* Copyright 2007 Maarten Maathuis
* Copyright 2007-2009 Stuart Bennett
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include "nouveau_drm.h"
#include "nouveau_encoder.h"
#include "nouveau_connector.h"
#include "nouveau_crtc.h"
#include "hw.h"
#include "nvreg.h"
#include <subdev/bios/gpio.h>
#include <subdev/gpio.h>
#include <subdev/timer.h>
int nv04_dac_output_offset(struct drm_encoder *encoder)
{
struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
int offset = 0;
if (dcb->or & (8 | DCB_OUTPUT_C))
offset += 0x68;
if (dcb->or & (8 | DCB_OUTPUT_B))
offset += 0x2000;
return offset;
}
/*
* arbitrary limit to number of sense oscillations tolerated in one sample
* period (observed to be at least 13 in "nvidia")
*/
#define MAX_HBLANK_OSC 20
/*
* arbitrary limit to number of conflicting sample pairs to tolerate at a
* voltage step (observed to be at least 5 in "nvidia")
*/
#define MAX_SAMPLE_PAIRS 10
static int sample_load_twice(struct drm_device *dev, bool sense[2])
{
struct nvif_device *device = &nouveau_drm(dev)->device;
struct nouveau_timer *ptimer = nvkm_timer(device);
int i;
for (i = 0; i < 2; i++) {
bool sense_a, sense_b, sense_b_prime;
int j = 0;
/*
* wait for bit 0 clear -- out of hblank -- (say reg value 0x4),
* then wait for transition 0x4->0x5->0x4: enter hblank, leave
* hblank again
* use a 10ms timeout (guards against crtc being inactive, in
* which case blank state would never change)
*/
if (!nouveau_timer_wait_eq(ptimer, 10000000,
NV_PRMCIO_INP0__COLOR,
0x00000001, 0x00000000))
return -EBUSY;
if (!nouveau_timer_wait_eq(ptimer, 10000000,
NV_PRMCIO_INP0__COLOR,
0x00000001, 0x00000001))
return -EBUSY;
if (!nouveau_timer_wait_eq(ptimer, 10000000,
NV_PRMCIO_INP0__COLOR,
0x00000001, 0x00000000))
return -EBUSY;
udelay(100);
/* when level triggers, sense is _LO_ */
sense_a = nvif_rd08(device, NV_PRMCIO_INP0) & 0x10;
/* take another reading until it agrees with sense_a... */
do {
udelay(100);
sense_b = nvif_rd08(device, NV_PRMCIO_INP0) & 0x10;
if (sense_a != sense_b) {
sense_b_prime =
nvif_rd08(device, NV_PRMCIO_INP0) & 0x10;
if (sense_b == sense_b_prime) {
/* ... unless two consecutive subsequent
* samples agree; sense_a is replaced */
sense_a = sense_b;
/* force mis-match so we loop */
sense_b = !sense_a;
}
}
} while ((sense_a != sense_b) && ++j < MAX_HBLANK_OSC);
if (j == MAX_HBLANK_OSC)
/* with so much oscillation, default to sense:LO */
sense[i] = false;
else
sense[i] = sense_a;
}
return 0;
}
static enum drm_connector_status nv04_dac_detect(struct drm_encoder *encoder,
struct drm_connector *connector)
{
struct drm_device *dev = encoder->dev;
struct nvif_device *device = &nouveau_drm(dev)->device;
struct nouveau_drm *drm = nouveau_drm(dev);
uint8_t saved_seq1, saved_pi, saved_rpc1, saved_cr_mode;
uint8_t saved_palette0[3], saved_palette_mask;
uint32_t saved_rtest_ctrl, saved_rgen_ctrl;
int i;
uint8_t blue;
bool sense = true;
/*
* for this detection to work, there needs to be a mode set up on the
* CRTC. this is presumed to be the case
*/
if (nv_two_heads(dev))
/* only implemented for head A for now */
NVSetOwner(dev, 0);
saved_cr_mode = NVReadVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX);
NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode | 0x80);
saved_seq1 = NVReadVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX);
NVWriteVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX, saved_seq1 & ~0x20);
saved_rtest_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL);
NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL,
saved_rtest_ctrl & ~NV_PRAMDAC_TEST_CONTROL_PWRDWN_DAC_OFF);
msleep(10);
saved_pi = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX);
NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX,
saved_pi & ~(0x80 | MASK(NV_CIO_CRE_PIXEL_FORMAT)));
saved_rpc1 = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX);
NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX, saved_rpc1 & ~0xc0);
nvif_wr08(device, NV_PRMDIO_READ_MODE_ADDRESS, 0x0);
for (i = 0; i < 3; i++)
saved_palette0[i] = nvif_rd08(device, NV_PRMDIO_PALETTE_DATA);
saved_palette_mask = nvif_rd08(device, NV_PRMDIO_PIXEL_MASK);
nvif_wr08(device, NV_PRMDIO_PIXEL_MASK, 0);
saved_rgen_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL);
NVWriteRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL,
(saved_rgen_ctrl & ~(NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS |
NV_PRAMDAC_GENERAL_CONTROL_TERMINATION_75OHM)) |
NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON);
blue = 8; /* start of test range */
do {
bool sense_pair[2];
nvif_wr08(device, NV_PRMDIO_WRITE_MODE_ADDRESS, 0);
nvif_wr08(device, NV_PRMDIO_PALETTE_DATA, 0);
nvif_wr08(device, NV_PRMDIO_PALETTE_DATA, 0);
/* testing blue won't find monochrome monitors. I don't care */
nvif_wr08(device, NV_PRMDIO_PALETTE_DATA, blue);
i = 0;
/* take sample pairs until both samples in the pair agree */
do {
if (sample_load_twice(dev, sense_pair))
goto out;
} while ((sense_pair[0] != sense_pair[1]) &&
++i < MAX_SAMPLE_PAIRS);
if (i == MAX_SAMPLE_PAIRS)
/* too much oscillation defaults to LO */
sense = false;
else
sense = sense_pair[0];
/*
* if sense goes LO before blue ramps to 0x18, monitor is not connected.
* ergo, if blue gets to 0x18, monitor must be connected
*/
} while (++blue < 0x18 && sense);
out:
nvif_wr08(device, NV_PRMDIO_PIXEL_MASK, saved_palette_mask);
NVWriteRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL, saved_rgen_ctrl);
nvif_wr08(device, NV_PRMDIO_WRITE_MODE_ADDRESS, 0);
for (i = 0; i < 3; i++)
nvif_wr08(device, NV_PRMDIO_PALETTE_DATA, saved_palette0[i]);
NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL, saved_rtest_ctrl);
NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX, saved_pi);
NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX, saved_rpc1);
NVWriteVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX, saved_seq1);
NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode);
if (blue == 0x18) {
NV_DEBUG(drm, "Load detected on head A\n");
return connector_status_connected;
}
return connector_status_disconnected;
}
uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nvif_device *device = &nouveau_drm(dev)->device;
struct nouveau_gpio *gpio = nvkm_gpio(device);
struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder);
uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput,
saved_rtest_ctrl, saved_gpio0 = 0, saved_gpio1 = 0, temp, routput;
int head;
#define RGB_TEST_DATA(r, g, b) (r << 0 | g << 10 | b << 20)
dac.rar_limit
版权申诉
110 浏览量
2022-09-23
00:49:19
上传
评论
收藏 5KB RAR 举报
Kinonoyomeo
- 粉丝: 77
- 资源: 1万+
最新资源
- com.Gaggle.fun.GooseGooseDuck.apk
- FastBrowser 基于CefSharp浏览器 Chromium内核 C#、WPF界面绘制, mp3、mp4播放
- apache-tomcat-8.5.100.tar.gz
- namehfyz1234
- 14727758_202405291911557049.csv.zip
- hfyzname1234
- 基于Java ME无线网络移动端的俄罗斯方块游戏的实现(源码+使用文档)
- 第九届上海市大学生网络安全大赛暨“磐石行动”2024第二届全国高校网络安全攻防活动 MISC wifi密码
- B07-GA503-2补充.zip
- 基于Java蚁群算法路由选择可视化(源码+使用文档)
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈