mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-21 03:33:59 +08:00
Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-next
Nothing terribly exciting in here probably: - reworked thermal stuff from mupuf/I, has a chance of possibly working well enough when we get to being able to reclock.. - driver will report mmio access faults on chipsets where it's supported - will now sleep waiting on fences on nv84+ rather than polling - some cleanup of the internal fencing, looking towards sli/dmabuf sync - initial support for anx9805 dp/tmds encoder - nv50+ display fixes related to the above, and also might fix a few other issues - nicer error reporting (will log process names with channel errors) - various other random fixes * 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6: (87 commits) nouveau: ACPI support depends on X86 and X86_PLATFORM_DEVICES drm/nouveau/i2c: add support for ddc/aux, and dp link training on anx9805 drm/nv50: initial kms support for off-chip TMDS/DP encoders drm/nv50-/disp: initial supervisor support for off-chip encoders drm/nv50-/disp: initial work towards supporting external encoders drm/nv50-/kms: remove unnecessary wait-for-completion points drm/nv50-/disp: move DP link training to core and train from supervisor drm/nv50-/disp: handle supervisor tasks from workqueue drm/nouveau/i2c: create proper chipset-specific class implementations drm/nv50-/disp: 0x0000 is a valid udisp config value drm/nv50/devinit: reverse the logic for running encoder init scripts drm/nouveau/bios: store a type/mask hash in parsed dcb data drm/nouveau/i2c: extend type to 16-bits, add lookup-by-type function drm/nouveau/i2c: aux channels not necessarily on nvio drm/nouveau/i2c: fix a bit of a thinko in nv_wri2cr helper functions drm/nouveau/bios: parse external transmitter type if off-chip drm/nouveau: store i2c port pointer directly in nouveau_encoder drm/nouveau/i2c: handle i2c/aux mux outside of port lookup function drm/nv50/graph: avoid touching 400724, it doesn't exist drm/nouveau: Fix DPMS 1 on G4 Snowball, from snow white to coal black. ...
This commit is contained in:
commit
1f3a574a4b
81
Documentation/thermal/nouveau_thermal
Normal file
81
Documentation/thermal/nouveau_thermal
Normal file
@ -0,0 +1,81 @@
|
||||
Kernel driver nouveau
|
||||
===================
|
||||
|
||||
Supported chips:
|
||||
* NV43+
|
||||
|
||||
Authors: Martin Peres (mupuf) <martin.peres@labri.fr>
|
||||
|
||||
Description
|
||||
---------
|
||||
|
||||
This driver allows to read the GPU core temperature, drive the GPU fan and
|
||||
set temperature alarms.
|
||||
|
||||
Currently, due to the absence of in-kernel API to access HWMON drivers, Nouveau
|
||||
cannot access any of the i2c external monitoring chips it may find. If you
|
||||
have one of those, temperature and/or fan management through Nouveau's HWMON
|
||||
interface is likely not to work. This document may then not cover your situation
|
||||
entirely.
|
||||
|
||||
Temperature management
|
||||
--------------------
|
||||
|
||||
Temperature is exposed under as a read-only HWMON attribute temp1_input.
|
||||
|
||||
In order to protect the GPU from overheating, Nouveau supports 4 configurable
|
||||
temperature thresholds:
|
||||
|
||||
* Fan_boost: Fan speed is set to 100% when reaching this temperature;
|
||||
* Downclock: The GPU will be downclocked to reduce its power dissipation;
|
||||
* Critical: The GPU is put on hold to further lower power dissipation;
|
||||
* Shutdown: Shut the computer down to protect your GPU.
|
||||
|
||||
WARNING: Some of these thresholds may not be used by Nouveau depending
|
||||
on your chipset.
|
||||
|
||||
The default value for these thresholds comes from the GPU's vbios. These
|
||||
thresholds can be configured thanks to the following HWMON attributes:
|
||||
|
||||
* Fan_boost: temp1_auto_point1_temp and temp1_auto_point1_temp_hyst;
|
||||
* Downclock: temp1_max and temp1_max_hyst;
|
||||
* Critical: temp1_crit and temp1_crit_hyst;
|
||||
* Shutdown: temp1_emergency and temp1_emergency_hyst.
|
||||
|
||||
NOTE: Remember that the values are stored as milli degrees Celcius. Don't forget
|
||||
to multiply!
|
||||
|
||||
Fan management
|
||||
------------
|
||||
|
||||
Not all cards have a drivable fan. If you do, then the following HWMON
|
||||
attributes should be available:
|
||||
|
||||
* pwm1_enable: Current fan management mode (NONE, MANUAL or AUTO);
|
||||
* pwm1: Current PWM value (power percentage);
|
||||
* pwm1_min: The minimum PWM speed allowed;
|
||||
* pwm1_max: The maximum PWM speed allowed (bypassed when hitting Fan_boost);
|
||||
|
||||
You may also have the following attribute:
|
||||
|
||||
* fan1_input: Speed in RPM of your fan.
|
||||
|
||||
Your fan can be driven in different modes:
|
||||
|
||||
* 0: The fan is left untouched;
|
||||
* 1: The fan can be driven in manual (use pwm1 to change the speed);
|
||||
* 2; The fan is driven automatically depending on the temperature.
|
||||
|
||||
NOTE: Be sure to use the manual mode if you want to drive the fan speed manually
|
||||
|
||||
NOTE2: Not all fan management modes may be supported on all chipsets. We are
|
||||
working on it.
|
||||
|
||||
Bug reports
|
||||
---------
|
||||
|
||||
Thermal management on Nouveau is new and may not work on all cards. If you have
|
||||
inquiries, please ping mupuf on IRC (#nouveau, freenode).
|
||||
|
||||
Bug reports should be filled on Freedesktop's bug tracker. Please follow
|
||||
http://nouveau.freedesktop.org/wiki/Bugs
|
@ -11,8 +11,9 @@ config DRM_NOUVEAU
|
||||
select FRAMEBUFFER_CONSOLE if !EXPERT
|
||||
select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
|
||||
select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT
|
||||
select ACPI_WMI if ACPI
|
||||
select MXM_WMI if ACPI
|
||||
select X86_PLATFORM_DEVICES if ACPI && X86
|
||||
select ACPI_WMI if ACPI && X86
|
||||
select MXM_WMI if ACPI && X86
|
||||
select POWER_SUPPLY
|
||||
help
|
||||
Choose this option for open-source nVidia support.
|
||||
|
@ -11,6 +11,7 @@ nouveau-y := core/core/client.o
|
||||
nouveau-y += core/core/engctx.o
|
||||
nouveau-y += core/core/engine.o
|
||||
nouveau-y += core/core/enum.o
|
||||
nouveau-y += core/core/event.o
|
||||
nouveau-y += core/core/falcon.o
|
||||
nouveau-y += core/core/gpuobj.o
|
||||
nouveau-y += core/core/handle.o
|
||||
@ -40,6 +41,11 @@ nouveau-y += core/subdev/bios/mxm.o
|
||||
nouveau-y += core/subdev/bios/perf.o
|
||||
nouveau-y += core/subdev/bios/pll.o
|
||||
nouveau-y += core/subdev/bios/therm.o
|
||||
nouveau-y += core/subdev/bios/xpio.o
|
||||
nouveau-y += core/subdev/bus/nv04.o
|
||||
nouveau-y += core/subdev/bus/nv31.o
|
||||
nouveau-y += core/subdev/bus/nv50.o
|
||||
nouveau-y += core/subdev/bus/nvc0.o
|
||||
nouveau-y += core/subdev/clock/nv04.o
|
||||
nouveau-y += core/subdev/clock/nv40.o
|
||||
nouveau-y += core/subdev/clock/nv50.o
|
||||
@ -85,9 +91,16 @@ nouveau-y += core/subdev/gpio/base.o
|
||||
nouveau-y += core/subdev/gpio/nv10.o
|
||||
nouveau-y += core/subdev/gpio/nv50.o
|
||||
nouveau-y += core/subdev/gpio/nvd0.o
|
||||
nouveau-y += core/subdev/gpio/nve0.o
|
||||
nouveau-y += core/subdev/i2c/base.o
|
||||
nouveau-y += core/subdev/i2c/anx9805.o
|
||||
nouveau-y += core/subdev/i2c/aux.o
|
||||
nouveau-y += core/subdev/i2c/bit.o
|
||||
nouveau-y += core/subdev/i2c/nv04.o
|
||||
nouveau-y += core/subdev/i2c/nv4e.o
|
||||
nouveau-y += core/subdev/i2c/nv50.o
|
||||
nouveau-y += core/subdev/i2c/nv94.o
|
||||
nouveau-y += core/subdev/i2c/nvd0.o
|
||||
nouveau-y += core/subdev/ibus/nvc0.o
|
||||
nouveau-y += core/subdev/ibus/nve0.o
|
||||
nouveau-y += core/subdev/instmem/base.o
|
||||
@ -106,10 +119,15 @@ nouveau-y += core/subdev/mxm/mxms.o
|
||||
nouveau-y += core/subdev/mxm/nv50.o
|
||||
nouveau-y += core/subdev/therm/base.o
|
||||
nouveau-y += core/subdev/therm/fan.o
|
||||
nouveau-y += core/subdev/therm/fannil.o
|
||||
nouveau-y += core/subdev/therm/fanpwm.o
|
||||
nouveau-y += core/subdev/therm/fantog.o
|
||||
nouveau-y += core/subdev/therm/ic.o
|
||||
nouveau-y += core/subdev/therm/temp.o
|
||||
nouveau-y += core/subdev/therm/nv40.o
|
||||
nouveau-y += core/subdev/therm/nv50.o
|
||||
nouveau-y += core/subdev/therm/temp.o
|
||||
nouveau-y += core/subdev/therm/nva3.o
|
||||
nouveau-y += core/subdev/therm/nvd0.o
|
||||
nouveau-y += core/subdev/timer/base.o
|
||||
nouveau-y += core/subdev/timer/nv04.o
|
||||
nouveau-y += core/subdev/vm/base.o
|
||||
@ -132,6 +150,7 @@ nouveau-y += core/engine/copy/nvc0.o
|
||||
nouveau-y += core/engine/copy/nve0.o
|
||||
nouveau-y += core/engine/crypt/nv84.o
|
||||
nouveau-y += core/engine/crypt/nv98.o
|
||||
nouveau-y += core/engine/disp/base.o
|
||||
nouveau-y += core/engine/disp/nv04.o
|
||||
nouveau-y += core/engine/disp/nv50.o
|
||||
nouveau-y += core/engine/disp/nv84.o
|
||||
@ -141,11 +160,13 @@ 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/dport.o
|
||||
nouveau-y += core/engine/disp/hdanva3.o
|
||||
nouveau-y += core/engine/disp/hdanvd0.o
|
||||
nouveau-y += core/engine/disp/hdminv84.o
|
||||
nouveau-y += core/engine/disp/hdminva3.o
|
||||
nouveau-y += core/engine/disp/hdminvd0.o
|
||||
nouveau-y += core/engine/disp/piornv50.o
|
||||
nouveau-y += core/engine/disp/sornv50.o
|
||||
nouveau-y += core/engine/disp/sornv94.o
|
||||
nouveau-y += core/engine/disp/sornvd0.o
|
||||
@ -194,7 +215,8 @@ nouveau-y += nouveau_drm.o nouveau_chan.o nouveau_dma.o nouveau_fence.o
|
||||
nouveau-y += nouveau_irq.o nouveau_vga.o nouveau_agp.o
|
||||
nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o
|
||||
nouveau-y += nouveau_prime.o nouveau_abi16.o
|
||||
nouveau-y += nv04_fence.o nv10_fence.o nv50_fence.o nv84_fence.o nvc0_fence.o
|
||||
nouveau-y += nv04_fence.o nv10_fence.o nv17_fence.o
|
||||
nouveau-y += nv50_fence.o nv84_fence.o nvc0_fence.o
|
||||
|
||||
# drm/kms
|
||||
nouveau-y += nouveau_bios.o nouveau_fbcon.o nouveau_display.o
|
||||
@ -216,7 +238,9 @@ nouveau-y += nouveau_mem.o
|
||||
|
||||
# other random bits
|
||||
nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
|
||||
ifdef CONFIG_X86
|
||||
nouveau-$(CONFIG_ACPI) += nouveau_acpi.o
|
||||
endif
|
||||
nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
|
||||
|
||||
obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o
|
||||
|
@ -99,3 +99,13 @@ nouveau_client_fini(struct nouveau_client *client, bool suspend)
|
||||
nv_debug(client, "%s completed with %d\n", name[suspend], ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *
|
||||
nouveau_client_name(void *obj)
|
||||
{
|
||||
const char *client_name = "unknown";
|
||||
struct nouveau_client *client = nouveau_client(obj);
|
||||
if (client)
|
||||
client_name = client->name;
|
||||
return client_name;
|
||||
}
|
||||
|
@ -40,14 +40,15 @@ nouveau_enum_find(const struct nouveau_enum *en, u32 value)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
const struct nouveau_enum *
|
||||
nouveau_enum_print(const struct nouveau_enum *en, u32 value)
|
||||
{
|
||||
en = nouveau_enum_find(en, value);
|
||||
if (en)
|
||||
printk("%s", en->name);
|
||||
pr_cont("%s", en->name);
|
||||
else
|
||||
printk("(unknown enum 0x%08x)", value);
|
||||
pr_cont("(unknown enum 0x%08x)", value);
|
||||
return en;
|
||||
}
|
||||
|
||||
void
|
||||
@ -55,7 +56,7 @@ nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value)
|
||||
{
|
||||
while (bf->name) {
|
||||
if (value & bf->mask) {
|
||||
printk(" %s", bf->name);
|
||||
pr_cont(" %s", bf->name);
|
||||
value &= ~bf->mask;
|
||||
}
|
||||
|
||||
@ -63,5 +64,5 @@ nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value)
|
||||
}
|
||||
|
||||
if (value)
|
||||
printk(" (unknown bits 0x%08x)", value);
|
||||
pr_cont(" (unknown bits 0x%08x)", value);
|
||||
}
|
||||
|
106
drivers/gpu/drm/nouveau/core/core/event.c
Normal file
106
drivers/gpu/drm/nouveau/core/core/event.c
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2013 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.
|
||||
*/
|
||||
|
||||
#include <core/os.h>
|
||||
#include <core/event.h>
|
||||
|
||||
static void
|
||||
nouveau_event_put_locked(struct nouveau_event *event, int index,
|
||||
struct nouveau_eventh *handler)
|
||||
{
|
||||
if (!--event->index[index].refs)
|
||||
event->disable(event, index);
|
||||
list_del(&handler->head);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_event_put(struct nouveau_event *event, int index,
|
||||
struct nouveau_eventh *handler)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&event->lock, flags);
|
||||
if (index < event->index_nr)
|
||||
nouveau_event_put_locked(event, index, handler);
|
||||
spin_unlock_irqrestore(&event->lock, flags);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_event_get(struct nouveau_event *event, int index,
|
||||
struct nouveau_eventh *handler)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&event->lock, flags);
|
||||
if (index < event->index_nr) {
|
||||
list_add(&handler->head, &event->index[index].list);
|
||||
if (!event->index[index].refs++)
|
||||
event->enable(event, index);
|
||||
}
|
||||
spin_unlock_irqrestore(&event->lock, flags);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_event_trigger(struct nouveau_event *event, int index)
|
||||
{
|
||||
struct nouveau_eventh *handler, *temp;
|
||||
unsigned long flags;
|
||||
|
||||
if (index >= event->index_nr)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&event->lock, flags);
|
||||
list_for_each_entry_safe(handler, temp, &event->index[index].list, head) {
|
||||
if (handler->func(handler, index) == NVKM_EVENT_DROP) {
|
||||
nouveau_event_put_locked(event, index, handler);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&event->lock, flags);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_event_destroy(struct nouveau_event **pevent)
|
||||
{
|
||||
struct nouveau_event *event = *pevent;
|
||||
if (event) {
|
||||
kfree(event);
|
||||
*pevent = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_event_create(int index_nr, struct nouveau_event **pevent)
|
||||
{
|
||||
struct nouveau_event *event;
|
||||
int i;
|
||||
|
||||
event = *pevent = kzalloc(sizeof(*event) + index_nr *
|
||||
sizeof(event->index[0]), GFP_KERNEL);
|
||||
if (!event)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&event->lock);
|
||||
for (i = 0; i < index_nr; i++)
|
||||
INIT_LIST_HEAD(&event->index[i].list);
|
||||
event->index_nr = index_nr;
|
||||
return 0;
|
||||
}
|
@ -22,6 +22,7 @@
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/client.h>
|
||||
#include <core/falcon.h>
|
||||
#include <core/class.h>
|
||||
#include <core/enum.h>
|
||||
@ -100,8 +101,9 @@ nva3_copy_intr(struct nouveau_subdev *subdev)
|
||||
if (stat & 0x00000040) {
|
||||
nv_error(falcon, "DISPATCH_ERROR [");
|
||||
nouveau_enum_print(nva3_copy_isr_error_name, ssta);
|
||||
printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst << 12, subc, mthd, data);
|
||||
pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst << 12, nouveau_client_name(engctx), subc,
|
||||
mthd, data);
|
||||
nv_wo32(falcon, 0x004, 0x00000040);
|
||||
stat &= ~0x00000040;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/client.h>
|
||||
#include <core/os.h>
|
||||
#include <core/enum.h>
|
||||
#include <core/class.h>
|
||||
@ -126,10 +127,11 @@ nv84_crypt_intr(struct nouveau_subdev *subdev)
|
||||
chid = pfifo->chid(pfifo, engctx);
|
||||
|
||||
if (stat) {
|
||||
nv_error(priv, "");
|
||||
nv_error(priv, "%s", "");
|
||||
nouveau_bitfield_print(nv84_crypt_intr_mask, stat);
|
||||
printk(" ch %d [0x%010llx] mthd 0x%04x data 0x%08x\n",
|
||||
chid, (u64)inst << 12, mthd, data);
|
||||
pr_cont(" ch %d [0x%010llx %s] mthd 0x%04x data 0x%08x\n",
|
||||
chid, (u64)inst << 12, nouveau_client_name(engctx),
|
||||
mthd, data);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x102130, stat);
|
||||
|
@ -22,6 +22,7 @@
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/client.h>
|
||||
#include <core/os.h>
|
||||
#include <core/enum.h>
|
||||
#include <core/class.h>
|
||||
@ -102,8 +103,9 @@ nv98_crypt_intr(struct nouveau_subdev *subdev)
|
||||
if (stat & 0x00000040) {
|
||||
nv_error(priv, "DISPATCH_ERROR [");
|
||||
nouveau_enum_print(nv98_crypt_isr_error_name, ssta);
|
||||
printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n",
|
||||
chid, (u64)inst << 12, subc, mthd, data);
|
||||
pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n",
|
||||
chid, (u64)inst << 12, nouveau_client_name(engctx),
|
||||
subc, mthd, data);
|
||||
nv_wr32(priv, 0x087004, 0x00000040);
|
||||
stat &= ~0x00000040;
|
||||
}
|
||||
|
52
drivers/gpu/drm/nouveau/core/engine/disp/base.c
Normal file
52
drivers/gpu/drm/nouveau/core/engine/disp/base.c
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2013 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 <engine/disp.h>
|
||||
|
||||
void
|
||||
_nouveau_disp_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_disp *disp = (void *)object;
|
||||
nouveau_event_destroy(&disp->vblank);
|
||||
nouveau_engine_destroy(&disp->base);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_disp_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, int heads,
|
||||
const char *intname, const char *extname,
|
||||
int length, void **pobject)
|
||||
{
|
||||
struct nouveau_disp *disp;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_engine_create_(parent, engine, oclass, true,
|
||||
intname, extname, length, pobject);
|
||||
disp = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return nouveau_event_create(heads, &disp->vblank);
|
||||
}
|
346
drivers/gpu/drm/nouveau/core/engine/disp/dport.c
Normal file
346
drivers/gpu/drm/nouveau/core/engine/disp/dport.c
Normal file
@ -0,0 +1,346 @@
|
||||
/*
|
||||
* Copyright 2013 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 <subdev/bios.h>
|
||||
#include <subdev/bios/dcb.h>
|
||||
#include <subdev/bios/dp.h>
|
||||
#include <subdev/bios/init.h>
|
||||
#include <subdev/i2c.h>
|
||||
|
||||
#include <engine/disp.h>
|
||||
|
||||
#include "dport.h"
|
||||
|
||||
#define DBG(fmt, args...) nv_debug(dp->disp, "DP:%04x:%04x: " fmt, \
|
||||
dp->outp->hasht, dp->outp->hashm, ##args)
|
||||
#define ERR(fmt, args...) nv_error(dp->disp, "DP:%04x:%04x: " fmt, \
|
||||
dp->outp->hasht, dp->outp->hashm, ##args)
|
||||
|
||||
/******************************************************************************
|
||||
* link training
|
||||
*****************************************************************************/
|
||||
struct dp_state {
|
||||
const struct nouveau_dp_func *func;
|
||||
struct nouveau_disp *disp;
|
||||
struct dcb_output *outp;
|
||||
struct nvbios_dpout info;
|
||||
u8 version;
|
||||
struct nouveau_i2c_port *aux;
|
||||
int head;
|
||||
u8 dpcd[4];
|
||||
int link_nr;
|
||||
u32 link_bw;
|
||||
u8 stat[6];
|
||||
u8 conf[4];
|
||||
};
|
||||
|
||||
static int
|
||||
dp_set_link_config(struct dp_state *dp)
|
||||
{
|
||||
struct nouveau_disp *disp = dp->disp;
|
||||
struct nouveau_bios *bios = nouveau_bios(disp);
|
||||
struct nvbios_init init = {
|
||||
.subdev = nv_subdev(dp->disp),
|
||||
.bios = bios,
|
||||
.offset = 0x0000,
|
||||
.outp = dp->outp,
|
||||
.crtc = dp->head,
|
||||
.execute = 1,
|
||||
};
|
||||
u32 lnkcmp;
|
||||
u8 sink[2];
|
||||
|
||||
DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
|
||||
|
||||
/* set desired link configuration on the sink */
|
||||
sink[0] = dp->link_bw / 27000;
|
||||
sink[1] = dp->link_nr;
|
||||
if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
|
||||
sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
|
||||
|
||||
nv_wraux(dp->aux, DPCD_LC00, sink, 2);
|
||||
|
||||
/* set desired link configuration on the source */
|
||||
if ((lnkcmp = dp->info.lnkcmp)) {
|
||||
if (dp->version < 0x30) {
|
||||
while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp))
|
||||
lnkcmp += 4;
|
||||
init.offset = nv_ro16(bios, lnkcmp + 2);
|
||||
} else {
|
||||
while ((dp->link_bw / 27000) < nv_ro08(bios, lnkcmp))
|
||||
lnkcmp += 3;
|
||||
init.offset = nv_ro16(bios, lnkcmp + 1);
|
||||
}
|
||||
|
||||
nvbios_exec(&init);
|
||||
}
|
||||
|
||||
return dp->func->lnk_ctl(dp->disp, dp->outp, dp->head,
|
||||
dp->link_nr, dp->link_bw / 27000,
|
||||
dp->dpcd[DPCD_RC02] &
|
||||
DPCD_RC02_ENHANCED_FRAME_CAP);
|
||||
}
|
||||
|
||||
static void
|
||||
dp_set_training_pattern(struct dp_state *dp, u8 pattern)
|
||||
{
|
||||
u8 sink_tp;
|
||||
|
||||
DBG("training pattern %d\n", pattern);
|
||||
dp->func->pattern(dp->disp, dp->outp, dp->head, pattern);
|
||||
|
||||
nv_rdaux(dp->aux, DPCD_LC02, &sink_tp, 1);
|
||||
sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET;
|
||||
sink_tp |= pattern;
|
||||
nv_wraux(dp->aux, DPCD_LC02, &sink_tp, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
dp_link_train_commit(struct dp_state *dp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dp->link_nr; i++) {
|
||||
u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
|
||||
u8 lpre = (lane & 0x0c) >> 2;
|
||||
u8 lvsw = (lane & 0x03) >> 0;
|
||||
|
||||
dp->conf[i] = (lpre << 3) | lvsw;
|
||||
if (lvsw == 3)
|
||||
dp->conf[i] |= DPCD_LC03_MAX_SWING_REACHED;
|
||||
if (lpre == 3)
|
||||
dp->conf[i] |= DPCD_LC03_MAX_PRE_EMPHASIS_REACHED;
|
||||
|
||||
DBG("config lane %d %02x\n", i, dp->conf[i]);
|
||||
dp->func->drv_ctl(dp->disp, dp->outp, dp->head, i, lvsw, lpre);
|
||||
}
|
||||
|
||||
return nv_wraux(dp->aux, DPCD_LC03(0), dp->conf, 4);
|
||||
}
|
||||
|
||||
static int
|
||||
dp_link_train_update(struct dp_state *dp, u32 delay)
|
||||
{
|
||||
int ret;
|
||||
|
||||
udelay(delay);
|
||||
|
||||
ret = nv_rdaux(dp->aux, DPCD_LS02, dp->stat, 6);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
DBG("status %*ph\n", 6, dp->stat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dp_link_train_cr(struct dp_state *dp)
|
||||
{
|
||||
bool cr_done = false, abort = false;
|
||||
int voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
|
||||
int tries = 0, i;
|
||||
|
||||
dp_set_training_pattern(dp, 1);
|
||||
|
||||
do {
|
||||
if (dp_link_train_commit(dp) ||
|
||||
dp_link_train_update(dp, 100))
|
||||
break;
|
||||
|
||||
cr_done = true;
|
||||
for (i = 0; i < dp->link_nr; i++) {
|
||||
u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
|
||||
if (!(lane & DPCD_LS02_LANE0_CR_DONE)) {
|
||||
cr_done = false;
|
||||
if (dp->conf[i] & DPCD_LC03_MAX_SWING_REACHED)
|
||||
abort = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET) != voltage) {
|
||||
voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
|
||||
tries = 0;
|
||||
}
|
||||
} while (!cr_done && !abort && ++tries < 5);
|
||||
|
||||
return cr_done ? 0 : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
dp_link_train_eq(struct dp_state *dp)
|
||||
{
|
||||
bool eq_done, cr_done = true;
|
||||
int tries = 0, i;
|
||||
|
||||
dp_set_training_pattern(dp, 2);
|
||||
|
||||
do {
|
||||
if (dp_link_train_update(dp, 400))
|
||||
break;
|
||||
|
||||
eq_done = !!(dp->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE);
|
||||
for (i = 0; i < dp->link_nr && eq_done; i++) {
|
||||
u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
|
||||
if (!(lane & DPCD_LS02_LANE0_CR_DONE))
|
||||
cr_done = false;
|
||||
if (!(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
|
||||
!(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED))
|
||||
eq_done = false;
|
||||
}
|
||||
|
||||
if (dp_link_train_commit(dp))
|
||||
break;
|
||||
} while (!eq_done && cr_done && ++tries <= 5);
|
||||
|
||||
return eq_done ? 0 : -1;
|
||||
}
|
||||
|
||||
static void
|
||||
dp_link_train_init(struct dp_state *dp, bool spread)
|
||||
{
|
||||
struct nvbios_init init = {
|
||||
.subdev = nv_subdev(dp->disp),
|
||||
.bios = nouveau_bios(dp->disp),
|
||||
.outp = dp->outp,
|
||||
.crtc = dp->head,
|
||||
.execute = 1,
|
||||
};
|
||||
|
||||
/* set desired spread */
|
||||
if (spread)
|
||||
init.offset = dp->info.script[2];
|
||||
else
|
||||
init.offset = dp->info.script[3];
|
||||
nvbios_exec(&init);
|
||||
|
||||
/* pre-train script */
|
||||
init.offset = dp->info.script[0];
|
||||
nvbios_exec(&init);
|
||||
}
|
||||
|
||||
static void
|
||||
dp_link_train_fini(struct dp_state *dp)
|
||||
{
|
||||
struct nvbios_init init = {
|
||||
.subdev = nv_subdev(dp->disp),
|
||||
.bios = nouveau_bios(dp->disp),
|
||||
.outp = dp->outp,
|
||||
.crtc = dp->head,
|
||||
.execute = 1,
|
||||
};
|
||||
|
||||
/* post-train script */
|
||||
init.offset = dp->info.script[1],
|
||||
nvbios_exec(&init);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
|
||||
struct dcb_output *outp, int head, u32 datarate)
|
||||
{
|
||||
struct nouveau_bios *bios = nouveau_bios(disp);
|
||||
struct nouveau_i2c *i2c = nouveau_i2c(disp);
|
||||
struct dp_state _dp = {
|
||||
.disp = disp,
|
||||
.func = func,
|
||||
.outp = outp,
|
||||
.head = head,
|
||||
}, *dp = &_dp;
|
||||
const u32 bw_list[] = { 270000, 162000, 0 };
|
||||
const u32 *link_bw = bw_list;
|
||||
u8 hdr, cnt, len;
|
||||
u32 data;
|
||||
int ret;
|
||||
|
||||
/* find the bios displayport data relevant to this output */
|
||||
data = nvbios_dpout_match(bios, outp->hasht, outp->hashm, &dp->version,
|
||||
&hdr, &cnt, &len, &dp->info);
|
||||
if (!data) {
|
||||
ERR("bios data not found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* acquire the aux channel and fetch some info about the display */
|
||||
if (outp->location)
|
||||
dp->aux = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->extdev));
|
||||
else
|
||||
dp->aux = i2c->find(i2c, NV_I2C_TYPE_DCBI2C(outp->i2c_index));
|
||||
if (!dp->aux) {
|
||||
ERR("no aux channel?!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = nv_rdaux(dp->aux, 0x00000, dp->dpcd, sizeof(dp->dpcd));
|
||||
if (ret) {
|
||||
ERR("failed to read DPCD\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* adjust required bandwidth for 8B/10B coding overhead */
|
||||
datarate = (datarate / 8) * 10;
|
||||
|
||||
/* enable down-spreading and execute pre-train script from vbios */
|
||||
dp_link_train_init(dp, dp->dpcd[3] & 0x01);
|
||||
|
||||
/* start off at highest link rate supported by encoder and display */
|
||||
while (*link_bw > (dp->dpcd[1] * 27000))
|
||||
link_bw++;
|
||||
|
||||
while (link_bw[0]) {
|
||||
/* find minimum required lane count at this link rate */
|
||||
dp->link_nr = dp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT;
|
||||
while ((dp->link_nr >> 1) * link_bw[0] > datarate)
|
||||
dp->link_nr >>= 1;
|
||||
|
||||
/* drop link rate to minimum with this lane count */
|
||||
while ((link_bw[1] * dp->link_nr) > datarate)
|
||||
link_bw++;
|
||||
dp->link_bw = link_bw[0];
|
||||
|
||||
/* program selected link configuration */
|
||||
ret = dp_set_link_config(dp);
|
||||
if (ret == 0) {
|
||||
/* attempt to train the link at this configuration */
|
||||
memset(dp->stat, 0x00, sizeof(dp->stat));
|
||||
if (!dp_link_train_cr(dp) &&
|
||||
!dp_link_train_eq(dp))
|
||||
break;
|
||||
} else
|
||||
if (ret >= 1) {
|
||||
/* dp_set_link_config() handled training */
|
||||
break;
|
||||
}
|
||||
|
||||
/* retry at lower rate */
|
||||
link_bw++;
|
||||
}
|
||||
|
||||
/* finish link training */
|
||||
dp_set_training_pattern(dp, 0);
|
||||
|
||||
/* execute post-train script from vbios */
|
||||
dp_link_train_fini(dp);
|
||||
return true;
|
||||
}
|
78
drivers/gpu/drm/nouveau/core/engine/disp/dport.h
Normal file
78
drivers/gpu/drm/nouveau/core/engine/disp/dport.h
Normal file
@ -0,0 +1,78 @@
|
||||
#ifndef __NVKM_DISP_DPORT_H__
|
||||
#define __NVKM_DISP_DPORT_H__
|
||||
|
||||
/* DPCD Receiver Capabilities */
|
||||
#define DPCD_RC00 0x00000
|
||||
#define DPCD_RC00_DPCD_REV 0xff
|
||||
#define DPCD_RC01 0x00001
|
||||
#define DPCD_RC01_MAX_LINK_RATE 0xff
|
||||
#define DPCD_RC02 0x00002
|
||||
#define DPCD_RC02_ENHANCED_FRAME_CAP 0x80
|
||||
#define DPCD_RC02_MAX_LANE_COUNT 0x1f
|
||||
#define DPCD_RC03 0x00003
|
||||
#define DPCD_RC03_MAX_DOWNSPREAD 0x01
|
||||
|
||||
/* DPCD Link Configuration */
|
||||
#define DPCD_LC00 0x00100
|
||||
#define DPCD_LC00_LINK_BW_SET 0xff
|
||||
#define DPCD_LC01 0x00101
|
||||
#define DPCD_LC01_ENHANCED_FRAME_EN 0x80
|
||||
#define DPCD_LC01_LANE_COUNT_SET 0x1f
|
||||
#define DPCD_LC02 0x00102
|
||||
#define DPCD_LC02_TRAINING_PATTERN_SET 0x03
|
||||
#define DPCD_LC03(l) ((l) + 0x00103)
|
||||
#define DPCD_LC03_MAX_PRE_EMPHASIS_REACHED 0x20
|
||||
#define DPCD_LC03_PRE_EMPHASIS_SET 0x18
|
||||
#define DPCD_LC03_MAX_SWING_REACHED 0x04
|
||||
#define DPCD_LC03_VOLTAGE_SWING_SET 0x03
|
||||
|
||||
/* DPCD Link/Sink Status */
|
||||
#define DPCD_LS02 0x00202
|
||||
#define DPCD_LS02_LANE1_SYMBOL_LOCKED 0x40
|
||||
#define DPCD_LS02_LANE1_CHANNEL_EQ_DONE 0x20
|
||||
#define DPCD_LS02_LANE1_CR_DONE 0x10
|
||||
#define DPCD_LS02_LANE0_SYMBOL_LOCKED 0x04
|
||||
#define DPCD_LS02_LANE0_CHANNEL_EQ_DONE 0x02
|
||||
#define DPCD_LS02_LANE0_CR_DONE 0x01
|
||||
#define DPCD_LS03 0x00203
|
||||
#define DPCD_LS03_LANE3_SYMBOL_LOCKED 0x40
|
||||
#define DPCD_LS03_LANE3_CHANNEL_EQ_DONE 0x20
|
||||
#define DPCD_LS03_LANE3_CR_DONE 0x10
|
||||
#define DPCD_LS03_LANE2_SYMBOL_LOCKED 0x04
|
||||
#define DPCD_LS03_LANE2_CHANNEL_EQ_DONE 0x02
|
||||
#define DPCD_LS03_LANE2_CR_DONE 0x01
|
||||
#define DPCD_LS04 0x00204
|
||||
#define DPCD_LS04_LINK_STATUS_UPDATED 0x80
|
||||
#define DPCD_LS04_DOWNSTREAM_PORT_STATUS_CHANGED 0x40
|
||||
#define DPCD_LS04_INTERLANE_ALIGN_DONE 0x01
|
||||
#define DPCD_LS06 0x00206
|
||||
#define DPCD_LS06_LANE1_PRE_EMPHASIS 0xc0
|
||||
#define DPCD_LS06_LANE1_VOLTAGE_SWING 0x30
|
||||
#define DPCD_LS06_LANE0_PRE_EMPHASIS 0x0c
|
||||
#define DPCD_LS06_LANE0_VOLTAGE_SWING 0x03
|
||||
#define DPCD_LS07 0x00207
|
||||
#define DPCD_LS07_LANE3_PRE_EMPHASIS 0xc0
|
||||
#define DPCD_LS07_LANE3_VOLTAGE_SWING 0x30
|
||||
#define DPCD_LS07_LANE2_PRE_EMPHASIS 0x0c
|
||||
#define DPCD_LS07_LANE2_VOLTAGE_SWING 0x03
|
||||
|
||||
struct nouveau_disp;
|
||||
struct dcb_output;
|
||||
|
||||
struct nouveau_dp_func {
|
||||
int (*pattern)(struct nouveau_disp *, struct dcb_output *,
|
||||
int head, int pattern);
|
||||
int (*lnk_ctl)(struct nouveau_disp *, struct dcb_output *, int head,
|
||||
int link_nr, int link_bw, bool enh_frame);
|
||||
int (*drv_ctl)(struct nouveau_disp *, struct dcb_output *, int head,
|
||||
int lane, int swing, int preem);
|
||||
};
|
||||
|
||||
extern const struct nouveau_dp_func nv94_sor_dp_func;
|
||||
extern const struct nouveau_dp_func nvd0_sor_dp_func;
|
||||
extern const struct nouveau_dp_func nv50_pior_dp_func;
|
||||
|
||||
int nouveau_dp_train(struct nouveau_disp *, const struct nouveau_dp_func *,
|
||||
struct dcb_output *, int, u32);
|
||||
|
||||
#endif
|
@ -24,21 +24,33 @@
|
||||
|
||||
#include <engine/disp.h>
|
||||
|
||||
#include <core/event.h>
|
||||
#include <core/class.h>
|
||||
|
||||
struct nv04_disp_priv {
|
||||
struct nouveau_disp base;
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv04_disp_sclass[] = {
|
||||
{ NV04_DISP_CLASS, &nouveau_object_ofuncs },
|
||||
{},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Display engine implementation
|
||||
******************************************************************************/
|
||||
|
||||
static void
|
||||
nv04_disp_intr_vblank(struct nv04_disp_priv *priv, int crtc)
|
||||
nv04_disp_vblank_enable(struct nouveau_event *event, int head)
|
||||
{
|
||||
struct nouveau_disp *disp = &priv->base;
|
||||
if (disp->vblank.notify)
|
||||
disp->vblank.notify(disp->vblank.data, crtc);
|
||||
nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000001);
|
||||
}
|
||||
|
||||
static void
|
||||
nv04_disp_vblank_disable(struct nouveau_event *event, int head)
|
||||
{
|
||||
nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000000);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -49,25 +61,25 @@ nv04_disp_intr(struct nouveau_subdev *subdev)
|
||||
u32 crtc1 = nv_rd32(priv, 0x602100);
|
||||
|
||||
if (crtc0 & 0x00000001) {
|
||||
nv04_disp_intr_vblank(priv, 0);
|
||||
nouveau_event_trigger(priv->base.vblank, 0);
|
||||
nv_wr32(priv, 0x600100, 0x00000001);
|
||||
}
|
||||
|
||||
if (crtc1 & 0x00000001) {
|
||||
nv04_disp_intr_vblank(priv, 1);
|
||||
nouveau_event_trigger(priv->base.vblank, 1);
|
||||
nv_wr32(priv, 0x602100, 0x00000001);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv04_disp_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_disp_create(parent, engine, oclass, "DISPLAY",
|
||||
ret = nouveau_disp_create(parent, engine, oclass, 2, "DISPLAY",
|
||||
"display", &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
@ -75,6 +87,9 @@ nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
|
||||
nv_engine(priv)->sclass = nv04_disp_sclass;
|
||||
nv_subdev(priv)->intr = nv04_disp_intr;
|
||||
priv->base.vblank->priv = priv;
|
||||
priv->base.vblank->enable = nv04_disp_vblank_enable;
|
||||
priv->base.vblank->disable = nv04_disp_vblank_disable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include <core/handle.h>
|
||||
#include <core/class.h>
|
||||
|
||||
#include <engine/software.h>
|
||||
#include <engine/disp.h>
|
||||
|
||||
#include <subdev/bios.h>
|
||||
@ -37,7 +36,6 @@
|
||||
#include <subdev/bios/pll.h>
|
||||
#include <subdev/timer.h>
|
||||
#include <subdev/fb.h>
|
||||
#include <subdev/bar.h>
|
||||
#include <subdev/clock.h>
|
||||
|
||||
#include "nv50.h"
|
||||
@ -335,7 +333,7 @@ nv50_disp_sync_ctor(struct nouveau_object *parent,
|
||||
struct nv50_disp_dmac *dmac;
|
||||
int ret;
|
||||
|
||||
if (size < sizeof(*data) || args->head > 1)
|
||||
if (size < sizeof(*args) || args->head > 1)
|
||||
return -EINVAL;
|
||||
|
||||
ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
|
||||
@ -374,7 +372,7 @@ nv50_disp_ovly_ctor(struct nouveau_object *parent,
|
||||
struct nv50_disp_dmac *dmac;
|
||||
int ret;
|
||||
|
||||
if (size < sizeof(*data) || args->head > 1)
|
||||
if (size < sizeof(*args) || args->head > 1)
|
||||
return -EINVAL;
|
||||
|
||||
ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
|
||||
@ -543,6 +541,18 @@ nv50_disp_curs_ofuncs = {
|
||||
* Base display object
|
||||
******************************************************************************/
|
||||
|
||||
static void
|
||||
nv50_disp_base_vblank_enable(struct nouveau_event *event, int head)
|
||||
{
|
||||
nv_mask(event->priv, 0x61002c, (1 << head), (1 << head));
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_disp_base_vblank_disable(struct nouveau_event *event, int head)
|
||||
{
|
||||
nv_mask(event->priv, 0x61002c, (1 << head), (0 << head));
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_disp_base_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
@ -559,6 +569,9 @@ nv50_disp_base_ctor(struct nouveau_object *parent,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->base.vblank->priv = priv;
|
||||
priv->base.vblank->enable = nv50_disp_base_vblank_enable;
|
||||
priv->base.vblank->disable = nv50_disp_base_vblank_disable;
|
||||
return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht);
|
||||
}
|
||||
|
||||
@ -613,7 +626,7 @@ nv50_disp_base_init(struct nouveau_object *object)
|
||||
nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp);
|
||||
}
|
||||
|
||||
/* ... EXT caps */
|
||||
/* ... PIOR caps */
|
||||
for (i = 0; i < 3; i++) {
|
||||
tmp = nv_rd32(priv, 0x61e000 + (i * 0x800));
|
||||
nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp);
|
||||
@ -665,6 +678,9 @@ nv50_disp_base_omthds[] = {
|
||||
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
|
||||
{ DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
|
||||
{ DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
|
||||
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
|
||||
{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
|
||||
{ PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd },
|
||||
{},
|
||||
};
|
||||
|
||||
@ -756,50 +772,6 @@ nv50_disp_intr_error(struct nv50_disp_priv *priv)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(priv);
|
||||
struct nouveau_disp *disp = &priv->base;
|
||||
struct nouveau_software_chan *chan, *temp;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&disp->vblank.lock, flags);
|
||||
list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) {
|
||||
if (chan->vblank.crtc != crtc)
|
||||
continue;
|
||||
|
||||
if (nv_device(priv)->chipset >= 0xc0) {
|
||||
nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
|
||||
bar->flush(bar);
|
||||
nv_wr32(priv, 0x06000c,
|
||||
upper_32_bits(chan->vblank.offset));
|
||||
nv_wr32(priv, 0x060010,
|
||||
lower_32_bits(chan->vblank.offset));
|
||||
nv_wr32(priv, 0x060014, chan->vblank.value);
|
||||
} else {
|
||||
nv_wr32(priv, 0x001704, chan->vblank.channel);
|
||||
nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
|
||||
bar->flush(bar);
|
||||
if (nv_device(priv)->chipset == 0x50) {
|
||||
nv_wr32(priv, 0x001570, chan->vblank.offset);
|
||||
nv_wr32(priv, 0x001574, chan->vblank.value);
|
||||
} else {
|
||||
nv_wr32(priv, 0x060010, chan->vblank.offset);
|
||||
nv_wr32(priv, 0x060014, chan->vblank.value);
|
||||
}
|
||||
}
|
||||
|
||||
list_del(&chan->vblank.head);
|
||||
if (disp->vblank.put)
|
||||
disp->vblank.put(disp->vblank.data, crtc);
|
||||
}
|
||||
spin_unlock_irqrestore(&disp->vblank.lock, flags);
|
||||
|
||||
if (disp->vblank.notify)
|
||||
disp->vblank.notify(disp->vblank.data, crtc);
|
||||
}
|
||||
|
||||
static u16
|
||||
exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
|
||||
struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
|
||||
@ -811,8 +783,8 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
|
||||
if (outp < 4) {
|
||||
type = DCB_OUTPUT_ANALOG;
|
||||
mask = 0;
|
||||
} else {
|
||||
outp -= 4;
|
||||
} else
|
||||
if (outp < 8) {
|
||||
switch (ctrl & 0x00000f00) {
|
||||
case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
|
||||
case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
|
||||
@ -824,6 +796,17 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
|
||||
nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
|
||||
return 0x0000;
|
||||
}
|
||||
outp -= 4;
|
||||
} else {
|
||||
outp = outp - 8;
|
||||
type = 0x0010;
|
||||
mask = 0;
|
||||
switch (ctrl & 0x00000f00) {
|
||||
case 0x00000000: type |= priv->pior.type[outp]; break;
|
||||
default:
|
||||
nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl);
|
||||
return 0x0000;
|
||||
}
|
||||
}
|
||||
|
||||
mask = 0x00c0 & (mask << 6);
|
||||
@ -834,6 +817,10 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
|
||||
if (!data)
|
||||
return 0x0000;
|
||||
|
||||
/* off-chip encoders require matching the exact encoder type */
|
||||
if (dcb->location != 0)
|
||||
type |= dcb->extdev << 8;
|
||||
|
||||
return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info);
|
||||
}
|
||||
|
||||
@ -848,9 +835,11 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
|
||||
u32 ctrl = 0x00000000;
|
||||
int i;
|
||||
|
||||
/* DAC */
|
||||
for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
|
||||
ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
|
||||
|
||||
/* SOR */
|
||||
if (!(ctrl & (1 << head))) {
|
||||
if (nv_device(priv)->chipset < 0x90 ||
|
||||
nv_device(priv)->chipset == 0x92 ||
|
||||
@ -865,6 +854,13 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
|
||||
}
|
||||
}
|
||||
|
||||
/* PIOR */
|
||||
if (!(ctrl & (1 << head))) {
|
||||
for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
|
||||
ctrl = nv_rd32(priv, 0x610b84 + (i * 8));
|
||||
i += 8;
|
||||
}
|
||||
|
||||
if (!(ctrl & (1 << head)))
|
||||
return false;
|
||||
i--;
|
||||
@ -894,13 +890,15 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
|
||||
struct nvbios_outp info1;
|
||||
struct nvbios_ocfg info2;
|
||||
u8 ver, hdr, cnt, len;
|
||||
u16 data, conf;
|
||||
u32 ctrl = 0x00000000;
|
||||
u32 data, conf = ~0;
|
||||
int i;
|
||||
|
||||
/* DAC */
|
||||
for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
|
||||
ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
|
||||
|
||||
/* SOR */
|
||||
if (!(ctrl & (1 << head))) {
|
||||
if (nv_device(priv)->chipset < 0x90 ||
|
||||
nv_device(priv)->chipset == 0x92 ||
|
||||
@ -915,34 +913,46 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
|
||||
}
|
||||
}
|
||||
|
||||
/* PIOR */
|
||||
if (!(ctrl & (1 << head))) {
|
||||
for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
|
||||
ctrl = nv_rd32(priv, 0x610b80 + (i * 8));
|
||||
i += 8;
|
||||
}
|
||||
|
||||
if (!(ctrl & (1 << head)))
|
||||
return 0x0000;
|
||||
return conf;
|
||||
i--;
|
||||
|
||||
data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1);
|
||||
if (!data)
|
||||
return 0x0000;
|
||||
return conf;
|
||||
|
||||
switch (outp->type) {
|
||||
case DCB_OUTPUT_TMDS:
|
||||
if (outp->location == 0) {
|
||||
switch (outp->type) {
|
||||
case DCB_OUTPUT_TMDS:
|
||||
conf = (ctrl & 0x00000f00) >> 8;
|
||||
if (pclk >= 165000)
|
||||
conf |= 0x0100;
|
||||
break;
|
||||
case DCB_OUTPUT_LVDS:
|
||||
conf = priv->sor.lvdsconf;
|
||||
break;
|
||||
case DCB_OUTPUT_DP:
|
||||
conf = (ctrl & 0x00000f00) >> 8;
|
||||
break;
|
||||
case DCB_OUTPUT_ANALOG:
|
||||
default:
|
||||
conf = 0x00ff;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
conf = (ctrl & 0x00000f00) >> 8;
|
||||
if (pclk >= 165000)
|
||||
conf |= 0x0100;
|
||||
break;
|
||||
case DCB_OUTPUT_LVDS:
|
||||
conf = priv->sor.lvdsconf;
|
||||
break;
|
||||
case DCB_OUTPUT_DP:
|
||||
conf = (ctrl & 0x00000f00) >> 8;
|
||||
break;
|
||||
case DCB_OUTPUT_ANALOG:
|
||||
default:
|
||||
conf = 0x00ff;
|
||||
break;
|
||||
pclk = pclk / 2;
|
||||
}
|
||||
|
||||
data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2);
|
||||
if (data) {
|
||||
if (data && id < 0xff) {
|
||||
data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
|
||||
if (data) {
|
||||
struct nvbios_init init = {
|
||||
@ -954,13 +964,11 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
|
||||
.execute = 1,
|
||||
};
|
||||
|
||||
if (nvbios_exec(&init))
|
||||
return 0x0000;
|
||||
return conf;
|
||||
nvbios_exec(&init);
|
||||
}
|
||||
}
|
||||
|
||||
return 0x0000;
|
||||
return conf;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -973,7 +981,6 @@ nv50_disp_intr_unk10(struct nv50_disp_priv *priv, u32 super)
|
||||
exec_script(priv, head, 1);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x610024, 0x00000010);
|
||||
nv_wr32(priv, 0x610030, 0x80000000);
|
||||
}
|
||||
|
||||
@ -1088,7 +1095,6 @@ static void
|
||||
nv50_disp_intr_unk20(struct nv50_disp_priv *priv, u32 super)
|
||||
{
|
||||
struct dcb_output outp;
|
||||
u32 addr, mask, data;
|
||||
int head;
|
||||
|
||||
/* finish detaching encoder? */
|
||||
@ -1104,33 +1110,58 @@ nv50_disp_intr_unk20(struct nv50_disp_priv *priv, u32 super)
|
||||
struct nouveau_clock *clk = nouveau_clock(priv);
|
||||
clk->pll_set(clk, PLL_VPLL0 + head, pclk);
|
||||
}
|
||||
|
||||
nv_mask(priv, 0x614200 + head * 0x800, 0x0000000f, 0x00000000);
|
||||
}
|
||||
|
||||
/* (re)attach the relevant OR to the head */
|
||||
head = ffs((super & 0x00000180) >> 7) - 1;
|
||||
if (head >= 0) {
|
||||
u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
|
||||
u32 conf = exec_clkcmp(priv, head, 0, pclk, &outp);
|
||||
if (conf) {
|
||||
if (outp.type == DCB_OUTPUT_ANALOG) {
|
||||
addr = 0x614280 + (ffs(outp.or) - 1) * 0x800;
|
||||
mask = 0xffffffff;
|
||||
data = 0x00000000;
|
||||
} else {
|
||||
if (outp.type == DCB_OUTPUT_DP)
|
||||
nv50_disp_intr_unk20_dp(priv, &outp, pclk);
|
||||
addr = 0x614300 + (ffs(outp.or) - 1) * 0x800;
|
||||
mask = 0x00000707;
|
||||
data = (conf & 0x0100) ? 0x0101 : 0x0000;
|
||||
u32 hval, hreg = 0x614200 + (head * 0x800);
|
||||
u32 oval, oreg;
|
||||
u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp);
|
||||
if (conf != ~0) {
|
||||
if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) {
|
||||
u32 soff = (ffs(outp.or) - 1) * 0x08;
|
||||
u32 ctrl = nv_rd32(priv, 0x610798 + soff);
|
||||
u32 datarate;
|
||||
|
||||
switch ((ctrl & 0x000f0000) >> 16) {
|
||||
case 6: datarate = pclk * 30 / 8; break;
|
||||
case 5: datarate = pclk * 24 / 8; break;
|
||||
case 2:
|
||||
default:
|
||||
datarate = pclk * 18 / 8;
|
||||
break;
|
||||
}
|
||||
|
||||
nouveau_dp_train(&priv->base, priv->sor.dp,
|
||||
&outp, head, datarate);
|
||||
}
|
||||
|
||||
nv_mask(priv, addr, mask, data);
|
||||
exec_clkcmp(priv, head, 0, pclk, &outp);
|
||||
|
||||
if (!outp.location && outp.type == DCB_OUTPUT_ANALOG) {
|
||||
oreg = 0x614280 + (ffs(outp.or) - 1) * 0x800;
|
||||
oval = 0x00000000;
|
||||
hval = 0x00000000;
|
||||
} else
|
||||
if (!outp.location) {
|
||||
if (outp.type == DCB_OUTPUT_DP)
|
||||
nv50_disp_intr_unk20_dp(priv, &outp, pclk);
|
||||
oreg = 0x614300 + (ffs(outp.or) - 1) * 0x800;
|
||||
oval = (conf & 0x0100) ? 0x0101 : 0x0000;
|
||||
hval = 0x00000000;
|
||||
} else {
|
||||
oreg = 0x614380 + (ffs(outp.or) - 1) * 0x800;
|
||||
oval = 0x00000001;
|
||||
hval = 0x00000001;
|
||||
}
|
||||
|
||||
nv_mask(priv, hreg, 0x0000000f, hval);
|
||||
nv_mask(priv, oreg, 0x00000707, oval);
|
||||
}
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x610024, 0x00000020);
|
||||
nv_wr32(priv, 0x610030, 0x80000000);
|
||||
}
|
||||
|
||||
@ -1163,28 +1194,47 @@ nv50_disp_intr_unk40(struct nv50_disp_priv *priv, u32 super)
|
||||
if (head >= 0) {
|
||||
struct dcb_output outp;
|
||||
u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
|
||||
if (pclk && exec_clkcmp(priv, head, 1, pclk, &outp)) {
|
||||
if (outp.type == DCB_OUTPUT_TMDS)
|
||||
if (exec_clkcmp(priv, head, 1, pclk, &outp) != ~0) {
|
||||
if (outp.location == 0 && outp.type == DCB_OUTPUT_TMDS)
|
||||
nv50_disp_intr_unk40_tmds(priv, &outp);
|
||||
else
|
||||
if (outp.location == 1 && outp.type == DCB_OUTPUT_DP) {
|
||||
u32 soff = (ffs(outp.or) - 1) * 0x08;
|
||||
u32 ctrl = nv_rd32(priv, 0x610b84 + soff);
|
||||
u32 datarate;
|
||||
|
||||
switch ((ctrl & 0x000f0000) >> 16) {
|
||||
case 6: datarate = pclk * 30 / 8; break;
|
||||
case 5: datarate = pclk * 24 / 8; break;
|
||||
case 2:
|
||||
default:
|
||||
datarate = pclk * 18 / 8;
|
||||
break;
|
||||
}
|
||||
|
||||
nouveau_dp_train(&priv->base, priv->pior.dp,
|
||||
&outp, head, datarate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x610024, 0x00000040);
|
||||
nv_wr32(priv, 0x610030, 0x80000000);
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_disp_intr_super(struct nv50_disp_priv *priv, u32 intr1)
|
||||
void
|
||||
nv50_disp_intr_supervisor(struct work_struct *work)
|
||||
{
|
||||
struct nv50_disp_priv *priv =
|
||||
container_of(work, struct nv50_disp_priv, supervisor);
|
||||
u32 super = nv_rd32(priv, 0x610030);
|
||||
|
||||
nv_debug(priv, "supervisor 0x%08x 0x%08x\n", intr1, super);
|
||||
nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super);
|
||||
|
||||
if (intr1 & 0x00000010)
|
||||
if (priv->super & 0x00000010)
|
||||
nv50_disp_intr_unk10(priv, super);
|
||||
if (intr1 & 0x00000020)
|
||||
if (priv->super & 0x00000020)
|
||||
nv50_disp_intr_unk20(priv, super);
|
||||
if (intr1 & 0x00000040)
|
||||
if (priv->super & 0x00000040)
|
||||
nv50_disp_intr_unk40(priv, super);
|
||||
}
|
||||
|
||||
@ -1201,19 +1251,21 @@ nv50_disp_intr(struct nouveau_subdev *subdev)
|
||||
}
|
||||
|
||||
if (intr1 & 0x00000004) {
|
||||
nv50_disp_intr_vblank(priv, 0);
|
||||
nouveau_event_trigger(priv->base.vblank, 0);
|
||||
nv_wr32(priv, 0x610024, 0x00000004);
|
||||
intr1 &= ~0x00000004;
|
||||
}
|
||||
|
||||
if (intr1 & 0x00000008) {
|
||||
nv50_disp_intr_vblank(priv, 1);
|
||||
nouveau_event_trigger(priv->base.vblank, 1);
|
||||
nv_wr32(priv, 0x610024, 0x00000008);
|
||||
intr1 &= ~0x00000008;
|
||||
}
|
||||
|
||||
if (intr1 & 0x00000070) {
|
||||
nv50_disp_intr_super(priv, intr1);
|
||||
priv->super = (intr1 & 0x00000070);
|
||||
schedule_work(&priv->supervisor);
|
||||
nv_wr32(priv, 0x610024, priv->super);
|
||||
intr1 &= ~0x00000070;
|
||||
}
|
||||
}
|
||||
@ -1226,7 +1278,7 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nv50_disp_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
|
||||
ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
|
||||
"display", &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
@ -1235,16 +1287,17 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
nv_engine(priv)->sclass = nv50_disp_base_oclass;
|
||||
nv_engine(priv)->cclass = &nv50_disp_cclass;
|
||||
nv_subdev(priv)->intr = nv50_disp_intr;
|
||||
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
|
||||
priv->sclass = nv50_disp_sclass;
|
||||
priv->head.nr = 2;
|
||||
priv->dac.nr = 3;
|
||||
priv->sor.nr = 2;
|
||||
priv->pior.nr = 3;
|
||||
priv->dac.power = nv50_dac_power;
|
||||
priv->dac.sense = nv50_dac_sense;
|
||||
priv->sor.power = nv50_sor_power;
|
||||
|
||||
INIT_LIST_HEAD(&priv->base.vblank.list);
|
||||
spin_lock_init(&priv->base.vblank.lock);
|
||||
priv->pior.power = nv50_pior_power;
|
||||
priv->pior.dp = &nv50_pior_dp_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3,16 +3,22 @@
|
||||
|
||||
#include <core/parent.h>
|
||||
#include <core/namedb.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/ramht.h>
|
||||
#include <core/event.h>
|
||||
|
||||
#include <engine/dmaobj.h>
|
||||
#include <engine/disp.h>
|
||||
|
||||
struct dcb_output;
|
||||
#include "dport.h"
|
||||
|
||||
struct nv50_disp_priv {
|
||||
struct nouveau_disp base;
|
||||
struct nouveau_oclass *sclass;
|
||||
|
||||
struct work_struct supervisor;
|
||||
u32 super;
|
||||
|
||||
struct {
|
||||
int nr;
|
||||
} head;
|
||||
@ -26,23 +32,15 @@ struct nv50_disp_priv {
|
||||
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_init)(struct nv50_disp_priv *, int sor, int link,
|
||||
int head, u16 type, u16 mask, u32 data,
|
||||
struct dcb_output *);
|
||||
int (*dp_train_fini)(struct nv50_disp_priv *, int sor, int link,
|
||||
int head, u16 type, u16 mask, u32 data,
|
||||
struct dcb_output *);
|
||||
int (*dp_train)(struct nv50_disp_priv *, int sor, int link,
|
||||
u16 type, u16 mask, u32 data,
|
||||
struct dcb_output *);
|
||||
int (*dp_lnkctl)(struct nv50_disp_priv *, int sor, int link,
|
||||
int head, u16 type, u16 mask, u32 data,
|
||||
struct dcb_output *);
|
||||
int (*dp_drvctl)(struct nv50_disp_priv *, int sor, int link,
|
||||
int lane, u16 type, u16 mask, u32 data,
|
||||
struct dcb_output *);
|
||||
u32 lvdsconf;
|
||||
const struct nouveau_dp_func *dp;
|
||||
} sor;
|
||||
struct {
|
||||
int nr;
|
||||
int (*power)(struct nv50_disp_priv *, int ext, u32 data);
|
||||
u8 type[3];
|
||||
const struct nouveau_dp_func *dp;
|
||||
} pior;
|
||||
};
|
||||
|
||||
#define DAC_MTHD(n) (n), (n) + 0x03
|
||||
@ -81,6 +79,11 @@ int nvd0_sor_dp_lnkctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
|
||||
int nvd0_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
|
||||
struct dcb_output *);
|
||||
|
||||
#define PIOR_MTHD(n) (n), (n) + 0x03
|
||||
|
||||
int nv50_pior_mthd(struct nouveau_object *, u32, void *, u32);
|
||||
int nv50_pior_power(struct nv50_disp_priv *, int, u32);
|
||||
|
||||
struct nv50_disp_base {
|
||||
struct nouveau_parent base;
|
||||
struct nouveau_ramht *ramht;
|
||||
@ -124,6 +127,7 @@ extern struct nouveau_ofuncs nv50_disp_oimm_ofuncs;
|
||||
extern struct nouveau_ofuncs nv50_disp_curs_ofuncs;
|
||||
extern struct nouveau_ofuncs nv50_disp_base_ofuncs;
|
||||
extern struct nouveau_oclass nv50_disp_cclass;
|
||||
void nv50_disp_intr_supervisor(struct work_struct *);
|
||||
void nv50_disp_intr(struct nouveau_subdev *);
|
||||
|
||||
extern struct nouveau_omthds nv84_disp_base_omthds[];
|
||||
@ -137,6 +141,7 @@ extern struct nouveau_ofuncs nvd0_disp_oimm_ofuncs;
|
||||
extern struct nouveau_ofuncs nvd0_disp_curs_ofuncs;
|
||||
extern struct nouveau_ofuncs nvd0_disp_base_ofuncs;
|
||||
extern struct nouveau_oclass nvd0_disp_cclass;
|
||||
void nvd0_disp_intr_supervisor(struct work_struct *);
|
||||
void nvd0_disp_intr(struct nouveau_subdev *);
|
||||
|
||||
#endif
|
||||
|
@ -46,6 +46,9 @@ nv84_disp_base_omthds[] = {
|
||||
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
|
||||
{ DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
|
||||
{ DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
|
||||
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
|
||||
{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
|
||||
{ PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd },
|
||||
{},
|
||||
};
|
||||
|
||||
@ -63,7 +66,7 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nv50_disp_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
|
||||
ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
|
||||
"display", &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
@ -72,17 +75,18 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
nv_engine(priv)->sclass = nv84_disp_base_oclass;
|
||||
nv_engine(priv)->cclass = &nv50_disp_cclass;
|
||||
nv_subdev(priv)->intr = nv50_disp_intr;
|
||||
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
|
||||
priv->sclass = nv84_disp_sclass;
|
||||
priv->head.nr = 2;
|
||||
priv->dac.nr = 3;
|
||||
priv->sor.nr = 2;
|
||||
priv->pior.nr = 3;
|
||||
priv->dac.power = nv50_dac_power;
|
||||
priv->dac.sense = nv50_dac_sense;
|
||||
priv->sor.power = nv50_sor_power;
|
||||
priv->sor.hdmi = nv84_hdmi_ctrl;
|
||||
|
||||
INIT_LIST_HEAD(&priv->base.vblank.list);
|
||||
spin_lock_init(&priv->base.vblank.lock);
|
||||
priv->pior.power = nv50_pior_power;
|
||||
priv->pior.dp = &nv50_pior_dp_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -44,14 +44,11 @@ nv94_disp_base_omthds[] = {
|
||||
{ SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
|
||||
{ SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
|
||||
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , 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 },
|
||||
{ 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 },
|
||||
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
|
||||
{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
|
||||
{ PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd },
|
||||
{},
|
||||
};
|
||||
|
||||
@ -69,7 +66,7 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nv50_disp_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
|
||||
ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
|
||||
"display", &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
@ -78,22 +75,19 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
nv_engine(priv)->sclass = nv94_disp_base_oclass;
|
||||
nv_engine(priv)->cclass = &nv50_disp_cclass;
|
||||
nv_subdev(priv)->intr = nv50_disp_intr;
|
||||
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
|
||||
priv->sclass = nv94_disp_sclass;
|
||||
priv->head.nr = 2;
|
||||
priv->dac.nr = 3;
|
||||
priv->sor.nr = 4;
|
||||
priv->pior.nr = 3;
|
||||
priv->dac.power = nv50_dac_power;
|
||||
priv->dac.sense = nv50_dac_sense;
|
||||
priv->sor.power = nv50_sor_power;
|
||||
priv->sor.hdmi = nv84_hdmi_ctrl;
|
||||
priv->sor.dp_train = nv94_sor_dp_train;
|
||||
priv->sor.dp_train_init = nv94_sor_dp_train_init;
|
||||
priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
|
||||
priv->sor.dp_lnkctl = nv94_sor_dp_lnkctl;
|
||||
priv->sor.dp_drvctl = nv94_sor_dp_drvctl;
|
||||
|
||||
INIT_LIST_HEAD(&priv->base.vblank.list);
|
||||
spin_lock_init(&priv->base.vblank.lock);
|
||||
priv->sor.dp = &nv94_sor_dp_func;
|
||||
priv->pior.power = nv50_pior_power;
|
||||
priv->pior.dp = &nv50_pior_dp_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nv50_disp_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
|
||||
ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
|
||||
"display", &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
@ -62,17 +62,18 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
nv_engine(priv)->sclass = nva0_disp_base_oclass;
|
||||
nv_engine(priv)->cclass = &nv50_disp_cclass;
|
||||
nv_subdev(priv)->intr = nv50_disp_intr;
|
||||
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
|
||||
priv->sclass = nva0_disp_sclass;
|
||||
priv->head.nr = 2;
|
||||
priv->dac.nr = 3;
|
||||
priv->sor.nr = 2;
|
||||
priv->pior.nr = 3;
|
||||
priv->dac.power = nv50_dac_power;
|
||||
priv->dac.sense = nv50_dac_sense;
|
||||
priv->sor.power = nv50_sor_power;
|
||||
priv->sor.hdmi = nv84_hdmi_ctrl;
|
||||
|
||||
INIT_LIST_HEAD(&priv->base.vblank.list);
|
||||
spin_lock_init(&priv->base.vblank.lock);
|
||||
priv->pior.power = nv50_pior_power;
|
||||
priv->pior.dp = &nv50_pior_dp_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -45,14 +45,11 @@ nva3_disp_base_omthds[] = {
|
||||
{ SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd },
|
||||
{ SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
|
||||
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , 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 },
|
||||
{ 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 },
|
||||
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
|
||||
{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
|
||||
{ PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd },
|
||||
{},
|
||||
};
|
||||
|
||||
@ -70,7 +67,7 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nv50_disp_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
|
||||
ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
|
||||
"display", &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
@ -79,23 +76,20 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
nv_engine(priv)->sclass = nva3_disp_base_oclass;
|
||||
nv_engine(priv)->cclass = &nv50_disp_cclass;
|
||||
nv_subdev(priv)->intr = nv50_disp_intr;
|
||||
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
|
||||
priv->sclass = nva3_disp_sclass;
|
||||
priv->head.nr = 2;
|
||||
priv->dac.nr = 3;
|
||||
priv->sor.nr = 4;
|
||||
priv->pior.nr = 3;
|
||||
priv->dac.power = nv50_dac_power;
|
||||
priv->dac.sense = nv50_dac_sense;
|
||||
priv->sor.power = nv50_sor_power;
|
||||
priv->sor.hda_eld = nva3_hda_eld;
|
||||
priv->sor.hdmi = nva3_hdmi_ctrl;
|
||||
priv->sor.dp_train = nv94_sor_dp_train;
|
||||
priv->sor.dp_train_init = nv94_sor_dp_train_init;
|
||||
priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
|
||||
priv->sor.dp_lnkctl = nv94_sor_dp_lnkctl;
|
||||
priv->sor.dp_drvctl = nv94_sor_dp_drvctl;
|
||||
|
||||
INIT_LIST_HEAD(&priv->base.vblank.list);
|
||||
spin_lock_init(&priv->base.vblank.lock);
|
||||
priv->sor.dp = &nv94_sor_dp_func;
|
||||
priv->pior.power = nv50_pior_power;
|
||||
priv->pior.dp = &nv50_pior_dp_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -27,12 +27,10 @@
|
||||
#include <core/handle.h>
|
||||
#include <core/class.h>
|
||||
|
||||
#include <engine/software.h>
|
||||
#include <engine/disp.h>
|
||||
|
||||
#include <subdev/timer.h>
|
||||
#include <subdev/fb.h>
|
||||
#include <subdev/bar.h>
|
||||
#include <subdev/clock.h>
|
||||
|
||||
#include <subdev/bios.h>
|
||||
@ -230,7 +228,7 @@ nvd0_disp_sync_ctor(struct nouveau_object *parent,
|
||||
struct nv50_disp_dmac *dmac;
|
||||
int ret;
|
||||
|
||||
if (size < sizeof(*data) || args->head >= priv->head.nr)
|
||||
if (size < sizeof(*args) || args->head >= priv->head.nr)
|
||||
return -EINVAL;
|
||||
|
||||
ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
|
||||
@ -270,7 +268,7 @@ nvd0_disp_ovly_ctor(struct nouveau_object *parent,
|
||||
struct nv50_disp_dmac *dmac;
|
||||
int ret;
|
||||
|
||||
if (size < sizeof(*data) || args->head >= priv->head.nr)
|
||||
if (size < sizeof(*args) || args->head >= priv->head.nr)
|
||||
return -EINVAL;
|
||||
|
||||
ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
|
||||
@ -443,6 +441,18 @@ nvd0_disp_curs_ofuncs = {
|
||||
* Base display object
|
||||
******************************************************************************/
|
||||
|
||||
static void
|
||||
nvd0_disp_base_vblank_enable(struct nouveau_event *event, int head)
|
||||
{
|
||||
nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001);
|
||||
}
|
||||
|
||||
static void
|
||||
nvd0_disp_base_vblank_disable(struct nouveau_event *event, int head)
|
||||
{
|
||||
nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000);
|
||||
}
|
||||
|
||||
static int
|
||||
nvd0_disp_base_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
@ -459,6 +469,10 @@ nvd0_disp_base_ctor(struct nouveau_object *parent,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->base.vblank->priv = priv;
|
||||
priv->base.vblank->enable = nvd0_disp_base_vblank_enable;
|
||||
priv->base.vblank->disable = nvd0_disp_base_vblank_disable;
|
||||
|
||||
return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht);
|
||||
}
|
||||
|
||||
@ -636,20 +650,19 @@ exec_script(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, int id)
|
||||
|
||||
static u32
|
||||
exec_clkcmp(struct nv50_disp_priv *priv, int head, int outp,
|
||||
u32 ctrl, int id, u32 pclk)
|
||||
u32 ctrl, int id, u32 pclk, struct dcb_output *dcb)
|
||||
{
|
||||
struct nouveau_bios *bios = nouveau_bios(priv);
|
||||
struct nvbios_outp info1;
|
||||
struct nvbios_ocfg info2;
|
||||
struct dcb_output dcb;
|
||||
u8 ver, hdr, cnt, len;
|
||||
u16 data, conf;
|
||||
u32 data, conf = ~0;
|
||||
|
||||
data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info1);
|
||||
data = exec_lookup(priv, head, outp, ctrl, dcb, &ver, &hdr, &cnt, &len, &info1);
|
||||
if (data == 0x0000)
|
||||
return false;
|
||||
return conf;
|
||||
|
||||
switch (dcb.type) {
|
||||
switch (dcb->type) {
|
||||
case DCB_OUTPUT_TMDS:
|
||||
conf = (ctrl & 0x00000f00) >> 8;
|
||||
if (pclk >= 165000)
|
||||
@ -668,25 +681,23 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int outp,
|
||||
}
|
||||
|
||||
data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2);
|
||||
if (data) {
|
||||
if (data && id < 0xff) {
|
||||
data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
|
||||
if (data) {
|
||||
struct nvbios_init init = {
|
||||
.subdev = nv_subdev(priv),
|
||||
.bios = bios,
|
||||
.offset = data,
|
||||
.outp = &dcb,
|
||||
.outp = dcb,
|
||||
.crtc = head,
|
||||
.execute = 1,
|
||||
};
|
||||
|
||||
if (nvbios_exec(&init))
|
||||
return 0x0000;
|
||||
return conf;
|
||||
nvbios_exec(&init);
|
||||
}
|
||||
}
|
||||
|
||||
return 0x0000;
|
||||
return conf;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -752,6 +763,7 @@ nvd0_display_unk2_calc_tu(struct nv50_disp_priv *priv, int head, int or)
|
||||
static void
|
||||
nvd0_display_unk2_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
|
||||
{
|
||||
struct dcb_output outp;
|
||||
u32 pclk;
|
||||
int i;
|
||||
|
||||
@ -771,10 +783,29 @@ nvd0_display_unk2_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
|
||||
nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000);
|
||||
|
||||
for (i = 0; mask && i < 8; i++) {
|
||||
u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20)), cfg;
|
||||
u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20));
|
||||
if (mcp & (1 << head)) {
|
||||
if ((cfg = exec_clkcmp(priv, head, i, mcp, 0, pclk))) {
|
||||
u32 cfg = exec_clkcmp(priv, head, i, mcp, 0xff, pclk, &outp);
|
||||
if (cfg != ~0) {
|
||||
u32 addr, mask, data = 0x00000000;
|
||||
|
||||
if (outp.type == DCB_OUTPUT_DP) {
|
||||
switch ((mcp & 0x000f0000) >> 16) {
|
||||
case 6: pclk = pclk * 30 / 8; break;
|
||||
case 5: pclk = pclk * 24 / 8; break;
|
||||
case 2:
|
||||
default:
|
||||
pclk = pclk * 18 / 8;
|
||||
break;
|
||||
}
|
||||
|
||||
nouveau_dp_train(&priv->base,
|
||||
priv->sor.dp,
|
||||
&outp, head, pclk);
|
||||
}
|
||||
|
||||
exec_clkcmp(priv, head, i, mcp, 0, pclk, &outp);
|
||||
|
||||
if (i < 4) {
|
||||
addr = 0x612280 + ((i - 0) * 0x800);
|
||||
mask = 0xffffffff;
|
||||
@ -807,6 +838,7 @@ nvd0_display_unk2_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
|
||||
static void
|
||||
nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
|
||||
{
|
||||
struct dcb_output outp;
|
||||
int pclk, i;
|
||||
|
||||
pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
|
||||
@ -814,7 +846,7 @@ nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
|
||||
for (i = 0; mask && i < 8; i++) {
|
||||
u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20));
|
||||
if (mcp & (1 << head))
|
||||
exec_clkcmp(priv, head, i, mcp, 1, pclk);
|
||||
exec_clkcmp(priv, head, i, mcp, 1, pclk, &outp);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x6101d4, 0x00000000);
|
||||
@ -822,33 +854,24 @@ nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
|
||||
nv_wr32(priv, 0x6101d0, 0x80000000);
|
||||
}
|
||||
|
||||
static void
|
||||
nvd0_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
|
||||
void
|
||||
nvd0_disp_intr_supervisor(struct work_struct *work)
|
||||
{
|
||||
struct nouveau_bar *bar = nouveau_bar(priv);
|
||||
struct nouveau_disp *disp = &priv->base;
|
||||
struct nouveau_software_chan *chan, *temp;
|
||||
unsigned long flags;
|
||||
struct nv50_disp_priv *priv =
|
||||
container_of(work, struct nv50_disp_priv, supervisor);
|
||||
u32 mask = 0, head = ~0;
|
||||
|
||||
spin_lock_irqsave(&disp->vblank.lock, flags);
|
||||
list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) {
|
||||
if (chan->vblank.crtc != crtc)
|
||||
continue;
|
||||
while (!mask && ++head < priv->head.nr)
|
||||
mask = nv_rd32(priv, 0x6101d4 + (head * 0x800));
|
||||
|
||||
nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
|
||||
bar->flush(bar);
|
||||
nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset));
|
||||
nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset));
|
||||
nv_wr32(priv, 0x060014, chan->vblank.value);
|
||||
nv_debug(priv, "supervisor %08x %08x %d\n", priv->super, mask, head);
|
||||
|
||||
list_del(&chan->vblank.head);
|
||||
if (disp->vblank.put)
|
||||
disp->vblank.put(disp->vblank.data, crtc);
|
||||
}
|
||||
spin_unlock_irqrestore(&disp->vblank.lock, flags);
|
||||
|
||||
if (disp->vblank.notify)
|
||||
disp->vblank.notify(disp->vblank.data, crtc);
|
||||
if (priv->super & 0x00000001)
|
||||
nvd0_display_unk1_handler(priv, head, mask);
|
||||
if (priv->super & 0x00000002)
|
||||
nvd0_display_unk2_handler(priv, head, mask);
|
||||
if (priv->super & 0x00000004)
|
||||
nvd0_display_unk4_handler(priv, head, mask);
|
||||
}
|
||||
|
||||
void
|
||||
@ -884,27 +907,11 @@ nvd0_disp_intr(struct nouveau_subdev *subdev)
|
||||
|
||||
if (intr & 0x00100000) {
|
||||
u32 stat = nv_rd32(priv, 0x6100ac);
|
||||
u32 mask = 0, crtc = ~0;
|
||||
|
||||
while (!mask && ++crtc < priv->head.nr)
|
||||
mask = nv_rd32(priv, 0x6101d4 + (crtc * 0x800));
|
||||
|
||||
if (stat & 0x00000001) {
|
||||
nv_wr32(priv, 0x6100ac, 0x00000001);
|
||||
nvd0_display_unk1_handler(priv, crtc, mask);
|
||||
stat &= ~0x00000001;
|
||||
}
|
||||
|
||||
if (stat & 0x00000002) {
|
||||
nv_wr32(priv, 0x6100ac, 0x00000002);
|
||||
nvd0_display_unk2_handler(priv, crtc, mask);
|
||||
stat &= ~0x00000002;
|
||||
}
|
||||
|
||||
if (stat & 0x00000004) {
|
||||
nv_wr32(priv, 0x6100ac, 0x00000004);
|
||||
nvd0_display_unk4_handler(priv, crtc, mask);
|
||||
stat &= ~0x00000004;
|
||||
if (stat & 0x00000007) {
|
||||
priv->super = (stat & 0x00000007);
|
||||
schedule_work(&priv->supervisor);
|
||||
nv_wr32(priv, 0x6100ac, priv->super);
|
||||
stat &= ~0x00000007;
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
@ -920,7 +927,7 @@ nvd0_disp_intr(struct nouveau_subdev *subdev)
|
||||
if (mask & intr) {
|
||||
u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
|
||||
if (stat & 0x00000001)
|
||||
nvd0_disp_intr_vblank(priv, i);
|
||||
nouveau_event_trigger(priv->base.vblank, i);
|
||||
nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
|
||||
nv_rd32(priv, 0x6100c0 + (i * 0x800));
|
||||
}
|
||||
@ -933,10 +940,11 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv50_disp_priv *priv;
|
||||
int heads = nv_rd32(parent, 0x022448);
|
||||
int ret;
|
||||
|
||||
ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
|
||||
"display", &priv);
|
||||
ret = nouveau_disp_create(parent, engine, oclass, heads,
|
||||
"PDISP", "display", &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -944,8 +952,9 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
nv_engine(priv)->sclass = nvd0_disp_base_oclass;
|
||||
nv_engine(priv)->cclass = &nv50_disp_cclass;
|
||||
nv_subdev(priv)->intr = nvd0_disp_intr;
|
||||
INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
|
||||
priv->sclass = nvd0_disp_sclass;
|
||||
priv->head.nr = nv_rd32(priv, 0x022448);
|
||||
priv->head.nr = heads;
|
||||
priv->dac.nr = 3;
|
||||
priv->sor.nr = 4;
|
||||
priv->dac.power = nv50_dac_power;
|
||||
@ -953,14 +962,7 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
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_train_init = nv94_sor_dp_train_init;
|
||||
priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
|
||||
priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl;
|
||||
priv->sor.dp_drvctl = nvd0_sor_dp_drvctl;
|
||||
|
||||
INIT_LIST_HEAD(&priv->base.vblank.list);
|
||||
spin_lock_init(&priv->base.vblank.lock);
|
||||
priv->sor.dp = &nvd0_sor_dp_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -51,10 +51,11 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv50_disp_priv *priv;
|
||||
int heads = nv_rd32(parent, 0x022448);
|
||||
int ret;
|
||||
|
||||
ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
|
||||
"display", &priv);
|
||||
ret = nouveau_disp_create(parent, engine, oclass, heads,
|
||||
"PDISP", "display", &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -62,8 +63,9 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
nv_engine(priv)->sclass = nve0_disp_base_oclass;
|
||||
nv_engine(priv)->cclass = &nv50_disp_cclass;
|
||||
nv_subdev(priv)->intr = nvd0_disp_intr;
|
||||
INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
|
||||
priv->sclass = nve0_disp_sclass;
|
||||
priv->head.nr = nv_rd32(priv, 0x022448);
|
||||
priv->head.nr = heads;
|
||||
priv->dac.nr = 3;
|
||||
priv->sor.nr = 4;
|
||||
priv->dac.power = nv50_dac_power;
|
||||
@ -71,14 +73,7 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
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_train_init = nv94_sor_dp_train_init;
|
||||
priv->sor.dp_train_fini = nv94_sor_dp_train_fini;
|
||||
priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl;
|
||||
priv->sor.dp_drvctl = nvd0_sor_dp_drvctl;
|
||||
|
||||
INIT_LIST_HEAD(&priv->base.vblank.list);
|
||||
spin_lock_init(&priv->base.vblank.lock);
|
||||
priv->sor.dp = &nvd0_sor_dp_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
140
drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c
Normal file
140
drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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 <core/os.h>
|
||||
#include <core/class.h>
|
||||
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bios/dcb.h>
|
||||
#include <subdev/timer.h>
|
||||
#include <subdev/i2c.h>
|
||||
|
||||
#include "nv50.h"
|
||||
|
||||
/******************************************************************************
|
||||
* DisplayPort
|
||||
*****************************************************************************/
|
||||
static struct nouveau_i2c_port *
|
||||
nv50_pior_dp_find(struct nouveau_disp *disp, struct dcb_output *outp)
|
||||
{
|
||||
struct nouveau_i2c *i2c = nouveau_i2c(disp);
|
||||
return i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->extdev));
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_pior_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp,
|
||||
int head, int pattern)
|
||||
{
|
||||
struct nouveau_i2c_port *port;
|
||||
int ret = -EINVAL;
|
||||
|
||||
port = nv50_pior_dp_find(disp, outp);
|
||||
if (port) {
|
||||
if (port->func->pattern)
|
||||
ret = port->func->pattern(port, pattern);
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_pior_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
|
||||
int head, int lane_nr, int link_bw, bool enh)
|
||||
{
|
||||
struct nouveau_i2c_port *port;
|
||||
int ret = -EINVAL;
|
||||
|
||||
port = nv50_pior_dp_find(disp, outp);
|
||||
if (port && port->func->lnk_ctl)
|
||||
ret = port->func->lnk_ctl(port, lane_nr, link_bw, enh);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_pior_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
|
||||
int head, int lane, int vsw, int pre)
|
||||
{
|
||||
struct nouveau_i2c_port *port;
|
||||
int ret = -EINVAL;
|
||||
|
||||
port = nv50_pior_dp_find(disp, outp);
|
||||
if (port) {
|
||||
if (port->func->drv_ctl)
|
||||
ret = port->func->drv_ctl(port, lane, vsw, pre);
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct nouveau_dp_func
|
||||
nv50_pior_dp_func = {
|
||||
.pattern = nv50_pior_dp_pattern,
|
||||
.lnk_ctl = nv50_pior_dp_lnk_ctl,
|
||||
.drv_ctl = nv50_pior_dp_drv_ctl,
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* General PIOR handling
|
||||
*****************************************************************************/
|
||||
int
|
||||
nv50_pior_power(struct nv50_disp_priv *priv, int or, u32 data)
|
||||
{
|
||||
const u32 stat = data & NV50_DISP_PIOR_PWR_STATE;
|
||||
const u32 soff = (or * 0x800);
|
||||
nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000);
|
||||
nv_mask(priv, 0x61e004 + soff, 0x80000101, 0x80000000 | stat);
|
||||
nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nv50_pior_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
|
||||
{
|
||||
struct nv50_disp_priv *priv = (void *)object->engine;
|
||||
const u8 type = (mthd & NV50_DISP_PIOR_MTHD_TYPE) >> 12;
|
||||
const u8 or = (mthd & NV50_DISP_PIOR_MTHD_OR);
|
||||
u32 *data = args;
|
||||
int ret;
|
||||
|
||||
if (size < sizeof(u32))
|
||||
return -EINVAL;
|
||||
|
||||
mthd &= ~NV50_DISP_PIOR_MTHD_TYPE;
|
||||
mthd &= ~NV50_DISP_PIOR_MTHD_OR;
|
||||
switch (mthd) {
|
||||
case NV50_DISP_PIOR_PWR:
|
||||
ret = priv->pior.power(priv, or, data[0]);
|
||||
priv->pior.type[or] = type;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
@ -79,31 +79,6 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
|
||||
priv->sor.lvdsconf = data & NV50_DISP_SOR_LVDS_SCRIPT_ID;
|
||||
ret = 0;
|
||||
break;
|
||||
case NV94_DISP_SOR_DP_TRAIN:
|
||||
switch (data & NV94_DISP_SOR_DP_TRAIN_OP) {
|
||||
case NV94_DISP_SOR_DP_TRAIN_OP_PATTERN:
|
||||
ret = priv->sor.dp_train(priv, or, link, type, mask, data, &outp);
|
||||
break;
|
||||
case NV94_DISP_SOR_DP_TRAIN_OP_INIT:
|
||||
ret = priv->sor.dp_train_init(priv, or, link, head, type, mask, data, &outp);
|
||||
break;
|
||||
case NV94_DISP_SOR_DP_TRAIN_OP_FINI:
|
||||
ret = priv->sor.dp_train_fini(priv, or, link, head, type, mask, data, &outp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NV94_DISP_SOR_DP_LNKCTL:
|
||||
ret = priv->sor.dp_lnkctl(priv, or, link, head, type, mask, data, &outp);
|
||||
break;
|
||||
case NV94_DISP_SOR_DP_DRVCTL(0):
|
||||
case NV94_DISP_SOR_DP_DRVCTL(1):
|
||||
case NV94_DISP_SOR_DP_DRVCTL(2):
|
||||
case NV94_DISP_SOR_DP_DRVCTL(3):
|
||||
ret = priv->sor.dp_drvctl(priv, or, link, (mthd & 0xc0) >> 6,
|
||||
type, mask, data, &outp);
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
}
|
||||
|
@ -32,6 +32,18 @@
|
||||
|
||||
#include "nv50.h"
|
||||
|
||||
static inline u32
|
||||
nv94_sor_soff(struct dcb_output *outp)
|
||||
{
|
||||
return (ffs(outp->or) - 1) * 0x800;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
nv94_sor_loff(struct dcb_output *outp)
|
||||
{
|
||||
return nv94_sor_soff(outp) + !(outp->sorconf.link & 1) * 0x80;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
nv94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
|
||||
{
|
||||
@ -42,115 +54,32 @@ nv94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
|
||||
return nv94[lane];
|
||||
}
|
||||
|
||||
int
|
||||
nv94_sor_dp_train_init(struct nv50_disp_priv *priv, int or, int link, int head,
|
||||
u16 type, u16 mask, u32 data, struct dcb_output *dcbo)
|
||||
static int
|
||||
nv94_sor_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp,
|
||||
int head, int pattern)
|
||||
{
|
||||
struct nouveau_bios *bios = nouveau_bios(priv);
|
||||
struct nvbios_dpout info;
|
||||
u8 ver, hdr, cnt, len;
|
||||
u16 outp;
|
||||
|
||||
outp = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &info);
|
||||
if (outp) {
|
||||
struct nvbios_init init = {
|
||||
.subdev = nv_subdev(priv),
|
||||
.bios = bios,
|
||||
.outp = dcbo,
|
||||
.crtc = head,
|
||||
.execute = 1,
|
||||
};
|
||||
|
||||
if (data & NV94_DISP_SOR_DP_TRAIN_INIT_SPREAD_ON)
|
||||
init.offset = info.script[2];
|
||||
else
|
||||
init.offset = info.script[3];
|
||||
nvbios_exec(&init);
|
||||
|
||||
init.offset = info.script[0];
|
||||
nvbios_exec(&init);
|
||||
}
|
||||
|
||||
struct nv50_disp_priv *priv = (void *)disp;
|
||||
const u32 loff = nv94_sor_loff(outp);
|
||||
nv_mask(priv, 0x61c10c + loff, 0x0f000000, pattern << 24);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nv94_sor_dp_train_fini(struct nv50_disp_priv *priv, int or, int link, int head,
|
||||
u16 type, u16 mask, u32 data, struct dcb_output *dcbo)
|
||||
static int
|
||||
nv94_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
|
||||
int head, int link_nr, int link_bw, bool enh_frame)
|
||||
{
|
||||
struct nouveau_bios *bios = nouveau_bios(priv);
|
||||
struct nvbios_dpout info;
|
||||
u8 ver, hdr, cnt, len;
|
||||
u16 outp;
|
||||
|
||||
outp = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &info);
|
||||
if (outp) {
|
||||
struct nvbios_init init = {
|
||||
.subdev = nv_subdev(priv),
|
||||
.bios = bios,
|
||||
.offset = info.script[1],
|
||||
.outp = dcbo,
|
||||
.crtc = head,
|
||||
.execute = 1,
|
||||
};
|
||||
|
||||
nvbios_exec(&init);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nv94_sor_dp_train(struct nv50_disp_priv *priv, int or, int link,
|
||||
u16 type, u16 mask, u32 data, struct dcb_output *info)
|
||||
{
|
||||
const u32 loff = (or * 0x800) + (link * 0x80);
|
||||
const u32 patt = (data & NV94_DISP_SOR_DP_TRAIN_PATTERN);
|
||||
nv_mask(priv, 0x61c10c + loff, 0x0f000000, patt << 24);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nv94_sor_dp_lnkctl(struct nv50_disp_priv *priv, int or, int link, int head,
|
||||
u16 type, u16 mask, u32 data, struct dcb_output *dcbo)
|
||||
{
|
||||
struct nouveau_bios *bios = nouveau_bios(priv);
|
||||
const u32 loff = (or * 0x800) + (link * 0x80);
|
||||
const u32 soff = (or * 0x800);
|
||||
u16 link_bw = (data & NV94_DISP_SOR_DP_LNKCTL_WIDTH) >> 8;
|
||||
u8 link_nr = (data & NV94_DISP_SOR_DP_LNKCTL_COUNT);
|
||||
struct nv50_disp_priv *priv = (void *)disp;
|
||||
const u32 soff = nv94_sor_soff(outp);
|
||||
const u32 loff = nv94_sor_loff(outp);
|
||||
u32 dpctrl = 0x00000000;
|
||||
u32 clksor = 0x00000000;
|
||||
u32 outp, lane = 0;
|
||||
u8 ver, hdr, cnt, len;
|
||||
struct nvbios_dpout info;
|
||||
u32 lane = 0;
|
||||
int i;
|
||||
|
||||
/* -> 10Khz units */
|
||||
link_bw *= 2700;
|
||||
|
||||
outp = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &info);
|
||||
if (outp && info.lnkcmp) {
|
||||
struct nvbios_init init = {
|
||||
.subdev = nv_subdev(priv),
|
||||
.bios = bios,
|
||||
.offset = 0x0000,
|
||||
.outp = dcbo,
|
||||
.crtc = head,
|
||||
.execute = 1,
|
||||
};
|
||||
|
||||
while (link_bw < nv_ro16(bios, info.lnkcmp))
|
||||
info.lnkcmp += 4;
|
||||
init.offset = nv_ro16(bios, info.lnkcmp + 2);
|
||||
|
||||
nvbios_exec(&init);
|
||||
}
|
||||
|
||||
dpctrl |= ((1 << link_nr) - 1) << 16;
|
||||
if (data & NV94_DISP_SOR_DP_LNKCTL_FRAME_ENH)
|
||||
if (enh_frame)
|
||||
dpctrl |= 0x00004000;
|
||||
if (link_bw > 16200)
|
||||
if (link_bw > 0x06)
|
||||
clksor |= 0x00040000;
|
||||
|
||||
for (i = 0; i < link_nr; i++)
|
||||
@ -162,24 +91,25 @@ nv94_sor_dp_lnkctl(struct nv50_disp_priv *priv, int or, int link, int head,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nv94_sor_dp_drvctl(struct nv50_disp_priv *priv, int or, int link, int lane,
|
||||
u16 type, u16 mask, u32 data, struct dcb_output *dcbo)
|
||||
static int
|
||||
nv94_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
|
||||
int head, int lane, int swing, int preem)
|
||||
{
|
||||
struct nouveau_bios *bios = nouveau_bios(priv);
|
||||
const u32 loff = (or * 0x800) + (link * 0x80);
|
||||
const u8 swing = (data & NV94_DISP_SOR_DP_DRVCTL_VS) >> 8;
|
||||
const u8 preem = (data & NV94_DISP_SOR_DP_DRVCTL_PE);
|
||||
struct nouveau_bios *bios = nouveau_bios(disp);
|
||||
struct nv50_disp_priv *priv = (void *)disp;
|
||||
const u32 loff = nv94_sor_loff(outp);
|
||||
u32 addr, shift = nv94_sor_dp_lane_map(priv, lane);
|
||||
u8 ver, hdr, cnt, len;
|
||||
struct nvbios_dpout outp;
|
||||
struct nvbios_dpout info;
|
||||
struct nvbios_dpcfg ocfg;
|
||||
|
||||
addr = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &outp);
|
||||
addr = nvbios_dpout_match(bios, outp->hasht, outp->hashm,
|
||||
&ver, &hdr, &cnt, &len, &info);
|
||||
if (!addr)
|
||||
return -ENODEV;
|
||||
|
||||
addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem, &ver, &hdr, &cnt, &len, &ocfg);
|
||||
addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem,
|
||||
&ver, &hdr, &cnt, &len, &ocfg);
|
||||
if (!addr)
|
||||
return -EINVAL;
|
||||
|
||||
@ -188,3 +118,10 @@ nv94_sor_dp_drvctl(struct nv50_disp_priv *priv, int or, int link, int lane,
|
||||
nv_mask(priv, 0x61c130 + loff, 0x0000ff00, ocfg.unk << 8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct nouveau_dp_func
|
||||
nv94_sor_dp_func = {
|
||||
.pattern = nv94_sor_dp_pattern,
|
||||
.lnk_ctl = nv94_sor_dp_lnk_ctl,
|
||||
.drv_ctl = nv94_sor_dp_drv_ctl,
|
||||
};
|
||||
|
@ -32,6 +32,18 @@
|
||||
|
||||
#include "nv50.h"
|
||||
|
||||
static inline u32
|
||||
nvd0_sor_soff(struct dcb_output *outp)
|
||||
{
|
||||
return (ffs(outp->or) - 1) * 0x800;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
nvd0_sor_loff(struct dcb_output *outp)
|
||||
{
|
||||
return nvd0_sor_soff(outp) + !(outp->sorconf.link & 1) * 0x80;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
nvd0_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
|
||||
{
|
||||
@ -39,53 +51,31 @@ nvd0_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
|
||||
return nvd0[lane];
|
||||
}
|
||||
|
||||
int
|
||||
nvd0_sor_dp_train(struct nv50_disp_priv *priv, int or, int link,
|
||||
u16 type, u16 mask, u32 data, struct dcb_output *info)
|
||||
static int
|
||||
nvd0_sor_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp,
|
||||
int head, int pattern)
|
||||
{
|
||||
const u32 loff = (or * 0x800) + (link * 0x80);
|
||||
const u32 patt = (data & NV94_DISP_SOR_DP_TRAIN_PATTERN);
|
||||
nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * patt);
|
||||
struct nv50_disp_priv *priv = (void *)disp;
|
||||
const u32 loff = nvd0_sor_loff(outp);
|
||||
nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nvd0_sor_dp_lnkctl(struct nv50_disp_priv *priv, int or, int link, int head,
|
||||
u16 type, u16 mask, u32 data, struct dcb_output *dcbo)
|
||||
static int
|
||||
nvd0_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
|
||||
int head, int link_nr, int link_bw, bool enh_frame)
|
||||
{
|
||||
struct nouveau_bios *bios = nouveau_bios(priv);
|
||||
const u32 loff = (or * 0x800) + (link * 0x80);
|
||||
const u32 soff = (or * 0x800);
|
||||
const u8 link_bw = (data & NV94_DISP_SOR_DP_LNKCTL_WIDTH) >> 8;
|
||||
const u8 link_nr = (data & NV94_DISP_SOR_DP_LNKCTL_COUNT);
|
||||
struct nv50_disp_priv *priv = (void *)disp;
|
||||
const u32 soff = nvd0_sor_soff(outp);
|
||||
const u32 loff = nvd0_sor_loff(outp);
|
||||
u32 dpctrl = 0x00000000;
|
||||
u32 clksor = 0x00000000;
|
||||
u32 outp, lane = 0;
|
||||
u8 ver, hdr, cnt, len;
|
||||
struct nvbios_dpout info;
|
||||
u32 lane = 0;
|
||||
int i;
|
||||
|
||||
outp = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &info);
|
||||
if (outp && info.lnkcmp) {
|
||||
struct nvbios_init init = {
|
||||
.subdev = nv_subdev(priv),
|
||||
.bios = bios,
|
||||
.offset = 0x0000,
|
||||
.outp = dcbo,
|
||||
.crtc = head,
|
||||
.execute = 1,
|
||||
};
|
||||
|
||||
while (nv_ro08(bios, info.lnkcmp) < link_bw)
|
||||
info.lnkcmp += 3;
|
||||
init.offset = nv_ro16(bios, info.lnkcmp + 1);
|
||||
|
||||
nvbios_exec(&init);
|
||||
}
|
||||
|
||||
clksor |= link_bw << 18;
|
||||
dpctrl |= ((1 << link_nr) - 1) << 16;
|
||||
if (data & NV94_DISP_SOR_DP_LNKCTL_FRAME_ENH)
|
||||
if (enh_frame)
|
||||
dpctrl |= 0x00004000;
|
||||
|
||||
for (i = 0; i < link_nr; i++)
|
||||
@ -97,24 +87,25 @@ nvd0_sor_dp_lnkctl(struct nv50_disp_priv *priv, int or, int link, int head,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nvd0_sor_dp_drvctl(struct nv50_disp_priv *priv, int or, int link, int lane,
|
||||
u16 type, u16 mask, u32 data, struct dcb_output *dcbo)
|
||||
static int
|
||||
nvd0_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp,
|
||||
int head, int lane, int swing, int preem)
|
||||
{
|
||||
struct nouveau_bios *bios = nouveau_bios(priv);
|
||||
const u32 loff = (or * 0x800) + (link * 0x80);
|
||||
const u8 swing = (data & NV94_DISP_SOR_DP_DRVCTL_VS) >> 8;
|
||||
const u8 preem = (data & NV94_DISP_SOR_DP_DRVCTL_PE);
|
||||
struct nouveau_bios *bios = nouveau_bios(disp);
|
||||
struct nv50_disp_priv *priv = (void *)disp;
|
||||
const u32 loff = nvd0_sor_loff(outp);
|
||||
u32 addr, shift = nvd0_sor_dp_lane_map(priv, lane);
|
||||
u8 ver, hdr, cnt, len;
|
||||
struct nvbios_dpout outp;
|
||||
struct nvbios_dpout info;
|
||||
struct nvbios_dpcfg ocfg;
|
||||
|
||||
addr = nvbios_dpout_match(bios, type, mask, &ver, &hdr, &cnt, &len, &outp);
|
||||
addr = nvbios_dpout_match(bios, outp->hasht, outp->hashm,
|
||||
&ver, &hdr, &cnt, &len, &info);
|
||||
if (!addr)
|
||||
return -ENODEV;
|
||||
|
||||
addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem, &ver, &hdr, &cnt, &len, &ocfg);
|
||||
addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem,
|
||||
&ver, &hdr, &cnt, &len, &ocfg);
|
||||
if (!addr)
|
||||
return -EINVAL;
|
||||
|
||||
@ -124,3 +115,10 @@ nvd0_sor_dp_drvctl(struct nv50_disp_priv *priv, int or, int link, int lane,
|
||||
nv_mask(priv, 0x61c13c + loff, 0x00000000, 0x00000000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct nouveau_dp_func
|
||||
nvd0_sor_dp_func = {
|
||||
.pattern = nvd0_sor_dp_pattern,
|
||||
.lnk_ctl = nvd0_sor_dp_lnk_ctl,
|
||||
.drv_ctl = nvd0_sor_dp_drv_ctl,
|
||||
};
|
||||
|
@ -22,8 +22,10 @@
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/client.h>
|
||||
#include <core/object.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/event.h>
|
||||
#include <core/class.h>
|
||||
|
||||
#include <engine/dmaobj.h>
|
||||
@ -146,10 +148,25 @@ nouveau_fifo_chid(struct nouveau_fifo *priv, struct nouveau_object *object)
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *
|
||||
nouveau_client_name_for_fifo_chid(struct nouveau_fifo *fifo, u32 chid)
|
||||
{
|
||||
struct nouveau_fifo_chan *chan = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&fifo->lock, flags);
|
||||
if (chid >= fifo->min && chid <= fifo->max)
|
||||
chan = (void *)fifo->channel[chid];
|
||||
spin_unlock_irqrestore(&fifo->lock, flags);
|
||||
|
||||
return nouveau_client_name(chan);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_fifo_destroy(struct nouveau_fifo *priv)
|
||||
{
|
||||
kfree(priv->channel);
|
||||
nouveau_event_destroy(&priv->uevent);
|
||||
nouveau_engine_destroy(&priv->base);
|
||||
}
|
||||
|
||||
@ -174,6 +191,10 @@ nouveau_fifo_create_(struct nouveau_object *parent,
|
||||
if (!priv->channel)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = nouveau_event_create(1, &priv->uevent);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->chid = nouveau_fifo_chid;
|
||||
spin_lock_init(&priv->lock);
|
||||
return 0;
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <core/namedb.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/ramht.h>
|
||||
#include <core/event.h>
|
||||
|
||||
#include <subdev/instmem.h>
|
||||
#include <subdev/instmem/nv04.h>
|
||||
@ -398,6 +399,98 @@ out:
|
||||
return handled;
|
||||
}
|
||||
|
||||
static void
|
||||
nv04_fifo_cache_error(struct nouveau_device *device,
|
||||
struct nv04_fifo_priv *priv, u32 chid, u32 get)
|
||||
{
|
||||
u32 mthd, data;
|
||||
int ptr;
|
||||
|
||||
/* NV_PFIFO_CACHE1_GET actually goes to 0xffc before wrapping on my
|
||||
* G80 chips, but CACHE1 isn't big enough for this much data.. Tests
|
||||
* show that it wraps around to the start at GET=0x800.. No clue as to
|
||||
* why..
|
||||
*/
|
||||
ptr = (get & 0x7ff) >> 2;
|
||||
|
||||
if (device->card_type < NV_40) {
|
||||
mthd = nv_rd32(priv, NV04_PFIFO_CACHE1_METHOD(ptr));
|
||||
data = nv_rd32(priv, NV04_PFIFO_CACHE1_DATA(ptr));
|
||||
} else {
|
||||
mthd = nv_rd32(priv, NV40_PFIFO_CACHE1_METHOD(ptr));
|
||||
data = nv_rd32(priv, NV40_PFIFO_CACHE1_DATA(ptr));
|
||||
}
|
||||
|
||||
if (!nv04_fifo_swmthd(priv, chid, mthd, data)) {
|
||||
const char *client_name =
|
||||
nouveau_client_name_for_fifo_chid(&priv->base, chid);
|
||||
nv_error(priv,
|
||||
"CACHE_ERROR - ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
|
||||
chid, client_name, (mthd >> 13) & 7, mthd & 0x1ffc,
|
||||
data);
|
||||
}
|
||||
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
|
||||
nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
|
||||
nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) & ~1);
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
|
||||
nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) | 1);
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0);
|
||||
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH,
|
||||
nv_rd32(priv, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
nv04_fifo_dma_pusher(struct nouveau_device *device, struct nv04_fifo_priv *priv,
|
||||
u32 chid)
|
||||
{
|
||||
const char *client_name;
|
||||
u32 dma_get = nv_rd32(priv, 0x003244);
|
||||
u32 dma_put = nv_rd32(priv, 0x003240);
|
||||
u32 push = nv_rd32(priv, 0x003220);
|
||||
u32 state = nv_rd32(priv, 0x003228);
|
||||
|
||||
client_name = nouveau_client_name_for_fifo_chid(&priv->base, chid);
|
||||
|
||||
if (device->card_type == NV_50) {
|
||||
u32 ho_get = nv_rd32(priv, 0x003328);
|
||||
u32 ho_put = nv_rd32(priv, 0x003320);
|
||||
u32 ib_get = nv_rd32(priv, 0x003334);
|
||||
u32 ib_put = nv_rd32(priv, 0x003330);
|
||||
|
||||
nv_error(priv,
|
||||
"DMA_PUSHER - ch %d [%s] get 0x%02x%08x put 0x%02x%08x ib_get 0x%08x ib_put 0x%08x state 0x%08x (err: %s) push 0x%08x\n",
|
||||
chid, client_name, ho_get, dma_get, ho_put, dma_put,
|
||||
ib_get, ib_put, state, nv_dma_state_err(state), push);
|
||||
|
||||
/* METHOD_COUNT, in DMA_STATE on earlier chipsets */
|
||||
nv_wr32(priv, 0x003364, 0x00000000);
|
||||
if (dma_get != dma_put || ho_get != ho_put) {
|
||||
nv_wr32(priv, 0x003244, dma_put);
|
||||
nv_wr32(priv, 0x003328, ho_put);
|
||||
} else
|
||||
if (ib_get != ib_put)
|
||||
nv_wr32(priv, 0x003334, ib_put);
|
||||
} else {
|
||||
nv_error(priv,
|
||||
"DMA_PUSHER - ch %d [%s] get 0x%08x put 0x%08x state 0x%08x (err: %s) push 0x%08x\n",
|
||||
chid, client_name, dma_get, dma_put, state,
|
||||
nv_dma_state_err(state), push);
|
||||
|
||||
if (dma_get != dma_put)
|
||||
nv_wr32(priv, 0x003244, dma_put);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x003228, 0x00000000);
|
||||
nv_wr32(priv, 0x003220, 0x00000001);
|
||||
nv_wr32(priv, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
|
||||
}
|
||||
|
||||
void
|
||||
nv04_fifo_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
@ -416,96 +509,12 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
|
||||
get = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
|
||||
|
||||
if (status & NV_PFIFO_INTR_CACHE_ERROR) {
|
||||
uint32_t mthd, data;
|
||||
int ptr;
|
||||
|
||||
/* NV_PFIFO_CACHE1_GET actually goes to 0xffc before
|
||||
* wrapping on my G80 chips, but CACHE1 isn't big
|
||||
* enough for this much data.. Tests show that it
|
||||
* wraps around to the start at GET=0x800.. No clue
|
||||
* as to why..
|
||||
*/
|
||||
ptr = (get & 0x7ff) >> 2;
|
||||
|
||||
if (device->card_type < NV_40) {
|
||||
mthd = nv_rd32(priv,
|
||||
NV04_PFIFO_CACHE1_METHOD(ptr));
|
||||
data = nv_rd32(priv,
|
||||
NV04_PFIFO_CACHE1_DATA(ptr));
|
||||
} else {
|
||||
mthd = nv_rd32(priv,
|
||||
NV40_PFIFO_CACHE1_METHOD(ptr));
|
||||
data = nv_rd32(priv,
|
||||
NV40_PFIFO_CACHE1_DATA(ptr));
|
||||
}
|
||||
|
||||
if (!nv04_fifo_swmthd(priv, chid, mthd, data)) {
|
||||
nv_error(priv, "CACHE_ERROR - Ch %d/%d "
|
||||
"Mthd 0x%04x Data 0x%08x\n",
|
||||
chid, (mthd >> 13) & 7, mthd & 0x1ffc,
|
||||
data);
|
||||
}
|
||||
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
|
||||
nv_wr32(priv, NV03_PFIFO_INTR_0,
|
||||
NV_PFIFO_INTR_CACHE_ERROR);
|
||||
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
|
||||
nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) & ~1);
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
|
||||
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
|
||||
nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) | 1);
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0);
|
||||
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH,
|
||||
nv_rd32(priv, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
|
||||
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
|
||||
|
||||
nv04_fifo_cache_error(device, priv, chid, get);
|
||||
status &= ~NV_PFIFO_INTR_CACHE_ERROR;
|
||||
}
|
||||
|
||||
if (status & NV_PFIFO_INTR_DMA_PUSHER) {
|
||||
u32 dma_get = nv_rd32(priv, 0x003244);
|
||||
u32 dma_put = nv_rd32(priv, 0x003240);
|
||||
u32 push = nv_rd32(priv, 0x003220);
|
||||
u32 state = nv_rd32(priv, 0x003228);
|
||||
|
||||
if (device->card_type == NV_50) {
|
||||
u32 ho_get = nv_rd32(priv, 0x003328);
|
||||
u32 ho_put = nv_rd32(priv, 0x003320);
|
||||
u32 ib_get = nv_rd32(priv, 0x003334);
|
||||
u32 ib_put = nv_rd32(priv, 0x003330);
|
||||
|
||||
nv_error(priv, "DMA_PUSHER - Ch %d Get 0x%02x%08x "
|
||||
"Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
|
||||
"State 0x%08x (err: %s) Push 0x%08x\n",
|
||||
chid, ho_get, dma_get, ho_put,
|
||||
dma_put, ib_get, ib_put, state,
|
||||
nv_dma_state_err(state),
|
||||
push);
|
||||
|
||||
/* METHOD_COUNT, in DMA_STATE on earlier chipsets */
|
||||
nv_wr32(priv, 0x003364, 0x00000000);
|
||||
if (dma_get != dma_put || ho_get != ho_put) {
|
||||
nv_wr32(priv, 0x003244, dma_put);
|
||||
nv_wr32(priv, 0x003328, ho_put);
|
||||
} else
|
||||
if (ib_get != ib_put) {
|
||||
nv_wr32(priv, 0x003334, ib_put);
|
||||
}
|
||||
} else {
|
||||
nv_error(priv, "DMA_PUSHER - Ch %d Get 0x%08x "
|
||||
"Put 0x%08x State 0x%08x (err: %s) Push 0x%08x\n",
|
||||
chid, dma_get, dma_put, state,
|
||||
nv_dma_state_err(state), push);
|
||||
|
||||
if (dma_get != dma_put)
|
||||
nv_wr32(priv, 0x003244, dma_put);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x003228, 0x00000000);
|
||||
nv_wr32(priv, 0x003220, 0x00000001);
|
||||
nv_wr32(priv, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
|
||||
nv04_fifo_dma_pusher(device, priv, chid);
|
||||
status &= ~NV_PFIFO_INTR_DMA_PUSHER;
|
||||
}
|
||||
|
||||
@ -528,6 +537,12 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
|
||||
status &= ~0x00000010;
|
||||
nv_wr32(priv, 0x002100, 0x00000010);
|
||||
}
|
||||
|
||||
if (status & 0x40000000) {
|
||||
nouveau_event_trigger(priv->base.uevent, 0);
|
||||
nv_wr32(priv, 0x002100, 0x40000000);
|
||||
status &= ~0x40000000;
|
||||
}
|
||||
}
|
||||
|
||||
if (status) {
|
||||
|
@ -129,7 +129,8 @@ nv50_fifo_context_detach(struct nouveau_object *parent, bool suspend,
|
||||
/* do the kickoff... */
|
||||
nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
|
||||
if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) {
|
||||
nv_error(priv, "channel %d unload timeout\n", chan->base.chid);
|
||||
nv_error(priv, "channel %d [%s] unload timeout\n",
|
||||
chan->base.chid, nouveau_client_name(chan));
|
||||
if (suspend)
|
||||
ret = -EBUSY;
|
||||
}
|
||||
@ -480,7 +481,7 @@ nv50_fifo_init(struct nouveau_object *object)
|
||||
nv_wr32(priv, 0x002044, 0x01003fff);
|
||||
|
||||
nv_wr32(priv, 0x002100, 0xffffffff);
|
||||
nv_wr32(priv, 0x002140, 0xffffffff);
|
||||
nv_wr32(priv, 0x002140, 0xbfffffff);
|
||||
|
||||
for (i = 0; i < 128; i++)
|
||||
nv_wr32(priv, 0x002600 + (i * 4), 0x00000000);
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <core/client.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/ramht.h>
|
||||
#include <core/event.h>
|
||||
#include <core/class.h>
|
||||
#include <core/math.h>
|
||||
|
||||
@ -100,7 +101,8 @@ nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend,
|
||||
done = nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff);
|
||||
nv_wr32(priv, 0x002520, save);
|
||||
if (!done) {
|
||||
nv_error(priv, "channel %d unload timeout\n", chan->base.chid);
|
||||
nv_error(priv, "channel %d [%s] unload timeout\n",
|
||||
chan->base.chid, nouveau_client_name(chan));
|
||||
if (suspend)
|
||||
return -EBUSY;
|
||||
}
|
||||
@ -378,6 +380,20 @@ nv84_fifo_cclass = {
|
||||
* PFIFO engine
|
||||
******************************************************************************/
|
||||
|
||||
static void
|
||||
nv84_fifo_uevent_enable(struct nouveau_event *event, int index)
|
||||
{
|
||||
struct nv84_fifo_priv *priv = event->priv;
|
||||
nv_mask(priv, 0x002140, 0x40000000, 0x40000000);
|
||||
}
|
||||
|
||||
static void
|
||||
nv84_fifo_uevent_disable(struct nouveau_event *event, int index)
|
||||
{
|
||||
struct nv84_fifo_priv *priv = event->priv;
|
||||
nv_mask(priv, 0x002140, 0x40000000, 0x00000000);
|
||||
}
|
||||
|
||||
static int
|
||||
nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
@ -401,6 +417,10 @@ nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->base.uevent->enable = nv84_fifo_uevent_enable;
|
||||
priv->base.uevent->disable = nv84_fifo_uevent_disable;
|
||||
priv->base.uevent->priv = priv;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00000100;
|
||||
nv_subdev(priv)->intr = nv04_fifo_intr;
|
||||
nv_engine(priv)->cclass = &nv84_fifo_cclass;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <core/namedb.h>
|
||||
#include <core/gpuobj.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/event.h>
|
||||
#include <core/class.h>
|
||||
#include <core/math.h>
|
||||
#include <core/enum.h>
|
||||
@ -149,7 +150,8 @@ nvc0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
|
||||
|
||||
nv_wr32(priv, 0x002634, chan->base.chid);
|
||||
if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
|
||||
nv_error(priv, "channel %d kick timeout\n", chan->base.chid);
|
||||
nv_error(priv, "channel %d [%s] kick timeout\n",
|
||||
chan->base.chid, nouveau_client_name(chan));
|
||||
if (suspend)
|
||||
return -EBUSY;
|
||||
}
|
||||
@ -333,17 +335,17 @@ nvc0_fifo_cclass = {
|
||||
******************************************************************************/
|
||||
|
||||
static const struct nouveau_enum nvc0_fifo_fault_unit[] = {
|
||||
{ 0x00, "PGRAPH" },
|
||||
{ 0x00, "PGRAPH", NULL, NVDEV_ENGINE_GR },
|
||||
{ 0x03, "PEEPHOLE" },
|
||||
{ 0x04, "BAR1" },
|
||||
{ 0x05, "BAR3" },
|
||||
{ 0x07, "PFIFO" },
|
||||
{ 0x10, "PBSP" },
|
||||
{ 0x11, "PPPP" },
|
||||
{ 0x07, "PFIFO", NULL, NVDEV_ENGINE_FIFO },
|
||||
{ 0x10, "PBSP", NULL, NVDEV_ENGINE_BSP },
|
||||
{ 0x11, "PPPP", NULL, NVDEV_ENGINE_PPP },
|
||||
{ 0x13, "PCOUNTER" },
|
||||
{ 0x14, "PVP" },
|
||||
{ 0x15, "PCOPY0" },
|
||||
{ 0x16, "PCOPY1" },
|
||||
{ 0x14, "PVP", NULL, NVDEV_ENGINE_VP },
|
||||
{ 0x15, "PCOPY0", NULL, NVDEV_ENGINE_COPY0 },
|
||||
{ 0x16, "PCOPY1", NULL, NVDEV_ENGINE_COPY1 },
|
||||
{ 0x17, "PDAEMON" },
|
||||
{}
|
||||
};
|
||||
@ -402,6 +404,9 @@ nvc0_fifo_isr_vm_fault(struct nvc0_fifo_priv *priv, int unit)
|
||||
u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10));
|
||||
u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10));
|
||||
u32 client = (stat & 0x00001f00) >> 8;
|
||||
const struct nouveau_enum *en;
|
||||
struct nouveau_engine *engine;
|
||||
struct nouveau_object *engctx = NULL;
|
||||
|
||||
switch (unit) {
|
||||
case 3: /* PEEPHOLE */
|
||||
@ -420,16 +425,26 @@ nvc0_fifo_isr_vm_fault(struct nvc0_fifo_priv *priv, int unit)
|
||||
nv_error(priv, "%s fault at 0x%010llx [", (stat & 0x00000080) ?
|
||||
"write" : "read", (u64)vahi << 32 | valo);
|
||||
nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f);
|
||||
printk("] from ");
|
||||
nouveau_enum_print(nvc0_fifo_fault_unit, unit);
|
||||
pr_cont("] from ");
|
||||
en = nouveau_enum_print(nvc0_fifo_fault_unit, unit);
|
||||
if (stat & 0x00000040) {
|
||||
printk("/");
|
||||
pr_cont("/");
|
||||
nouveau_enum_print(nvc0_fifo_fault_hubclient, client);
|
||||
} else {
|
||||
printk("/GPC%d/", (stat & 0x1f000000) >> 24);
|
||||
pr_cont("/GPC%d/", (stat & 0x1f000000) >> 24);
|
||||
nouveau_enum_print(nvc0_fifo_fault_gpcclient, client);
|
||||
}
|
||||
printk(" on channel 0x%010llx\n", (u64)inst << 12);
|
||||
|
||||
if (en && en->data2) {
|
||||
engine = nouveau_engine(priv, en->data2);
|
||||
if (engine)
|
||||
engctx = nouveau_engctx_get(engine, inst);
|
||||
|
||||
}
|
||||
pr_cont(" on channel 0x%010llx [%s]\n", (u64)inst << 12,
|
||||
nouveau_client_name(engctx));
|
||||
|
||||
nouveau_engctx_put(engctx);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -484,10 +499,12 @@ nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit)
|
||||
if (show) {
|
||||
nv_error(priv, "SUBFIFO%d:", unit);
|
||||
nouveau_bitfield_print(nvc0_fifo_subfifo_intr, show);
|
||||
printk("\n");
|
||||
nv_error(priv, "SUBFIFO%d: ch %d subc %d mthd 0x%04x "
|
||||
"data 0x%08x\n",
|
||||
unit, chid, subc, mthd, data);
|
||||
pr_cont("\n");
|
||||
nv_error(priv,
|
||||
"SUBFIFO%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
|
||||
unit, chid,
|
||||
nouveau_client_name_for_fifo_chid(&priv->base, chid),
|
||||
subc, mthd, data);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
|
||||
@ -501,12 +518,34 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev)
|
||||
u32 mask = nv_rd32(priv, 0x002140);
|
||||
u32 stat = nv_rd32(priv, 0x002100) & mask;
|
||||
|
||||
if (stat & 0x00000001) {
|
||||
u32 intr = nv_rd32(priv, 0x00252c);
|
||||
nv_warn(priv, "INTR 0x00000001: 0x%08x\n", intr);
|
||||
nv_wr32(priv, 0x002100, 0x00000001);
|
||||
stat &= ~0x00000001;
|
||||
}
|
||||
|
||||
if (stat & 0x00000100) {
|
||||
nv_warn(priv, "unknown status 0x00000100\n");
|
||||
u32 intr = nv_rd32(priv, 0x00254c);
|
||||
nv_warn(priv, "INTR 0x00000100: 0x%08x\n", intr);
|
||||
nv_wr32(priv, 0x002100, 0x00000100);
|
||||
stat &= ~0x00000100;
|
||||
}
|
||||
|
||||
if (stat & 0x00010000) {
|
||||
u32 intr = nv_rd32(priv, 0x00256c);
|
||||
nv_warn(priv, "INTR 0x00010000: 0x%08x\n", intr);
|
||||
nv_wr32(priv, 0x002100, 0x00010000);
|
||||
stat &= ~0x00010000;
|
||||
}
|
||||
|
||||
if (stat & 0x01000000) {
|
||||
u32 intr = nv_rd32(priv, 0x00258c);
|
||||
nv_warn(priv, "INTR 0x01000000: 0x%08x\n", intr);
|
||||
nv_wr32(priv, 0x002100, 0x01000000);
|
||||
stat &= ~0x01000000;
|
||||
}
|
||||
|
||||
if (stat & 0x10000000) {
|
||||
u32 units = nv_rd32(priv, 0x00259c);
|
||||
u32 u = units;
|
||||
@ -536,11 +575,20 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev)
|
||||
}
|
||||
|
||||
if (stat & 0x40000000) {
|
||||
nv_warn(priv, "unknown status 0x40000000\n");
|
||||
nv_mask(priv, 0x002a00, 0x00000000, 0x00000000);
|
||||
u32 intr0 = nv_rd32(priv, 0x0025a4);
|
||||
u32 intr1 = nv_mask(priv, 0x002a00, 0x00000000, 0x00000);
|
||||
nv_debug(priv, "INTR 0x40000000: 0x%08x 0x%08x\n",
|
||||
intr0, intr1);
|
||||
stat &= ~0x40000000;
|
||||
}
|
||||
|
||||
if (stat & 0x80000000) {
|
||||
u32 intr = nv_mask(priv, 0x0025a8, 0x00000000, 0x00000000);
|
||||
nouveau_event_trigger(priv->base.uevent, 0);
|
||||
nv_debug(priv, "INTR 0x80000000: 0x%08x\n", intr);
|
||||
stat &= ~0x80000000;
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
nv_fatal(priv, "unhandled status 0x%08x\n", stat);
|
||||
nv_wr32(priv, 0x002100, stat);
|
||||
@ -548,6 +596,20 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nvc0_fifo_uevent_enable(struct nouveau_event *event, int index)
|
||||
{
|
||||
struct nvc0_fifo_priv *priv = event->priv;
|
||||
nv_mask(priv, 0x002140, 0x80000000, 0x80000000);
|
||||
}
|
||||
|
||||
static void
|
||||
nvc0_fifo_uevent_disable(struct nouveau_event *event, int index)
|
||||
{
|
||||
struct nvc0_fifo_priv *priv = event->priv;
|
||||
nv_mask(priv, 0x002140, 0x80000000, 0x00000000);
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
@ -581,6 +643,10 @@ nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->base.uevent->enable = nvc0_fifo_uevent_enable;
|
||||
priv->base.uevent->disable = nvc0_fifo_uevent_disable;
|
||||
priv->base.uevent->priv = priv;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00000100;
|
||||
nv_subdev(priv)->intr = nvc0_fifo_intr;
|
||||
nv_engine(priv)->cclass = &nvc0_fifo_cclass;
|
||||
@ -639,7 +705,8 @@ nvc0_fifo_init(struct nouveau_object *object)
|
||||
|
||||
nv_wr32(priv, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */
|
||||
nv_wr32(priv, 0x002100, 0xffffffff);
|
||||
nv_wr32(priv, 0x002140, 0xbfffffff);
|
||||
nv_wr32(priv, 0x002140, 0x3fffffff);
|
||||
nv_wr32(priv, 0x002628, 0x00000001); /* makes mthd 0x20 work */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <core/namedb.h>
|
||||
#include <core/gpuobj.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/event.h>
|
||||
#include <core/class.h>
|
||||
#include <core/math.h>
|
||||
#include <core/enum.h>
|
||||
@ -184,7 +185,8 @@ nve0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
|
||||
|
||||
nv_wr32(priv, 0x002634, chan->base.chid);
|
||||
if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
|
||||
nv_error(priv, "channel %d kick timeout\n", chan->base.chid);
|
||||
nv_error(priv, "channel %d [%s] kick timeout\n",
|
||||
chan->base.chid, nouveau_client_name(chan));
|
||||
if (suspend)
|
||||
return -EBUSY;
|
||||
}
|
||||
@ -412,20 +414,34 @@ nve0_fifo_isr_vm_fault(struct nve0_fifo_priv *priv, int unit)
|
||||
u32 vahi = nv_rd32(priv, 0x2808 + (unit * 0x10));
|
||||
u32 stat = nv_rd32(priv, 0x280c + (unit * 0x10));
|
||||
u32 client = (stat & 0x00001f00) >> 8;
|
||||
const struct nouveau_enum *en;
|
||||
struct nouveau_engine *engine;
|
||||
struct nouveau_object *engctx = NULL;
|
||||
|
||||
nv_error(priv, "PFIFO: %s fault at 0x%010llx [", (stat & 0x00000080) ?
|
||||
"write" : "read", (u64)vahi << 32 | valo);
|
||||
nouveau_enum_print(nve0_fifo_fault_reason, stat & 0x0000000f);
|
||||
printk("] from ");
|
||||
nouveau_enum_print(nve0_fifo_fault_unit, unit);
|
||||
pr_cont("] from ");
|
||||
en = nouveau_enum_print(nve0_fifo_fault_unit, unit);
|
||||
if (stat & 0x00000040) {
|
||||
printk("/");
|
||||
pr_cont("/");
|
||||
nouveau_enum_print(nve0_fifo_fault_hubclient, client);
|
||||
} else {
|
||||
printk("/GPC%d/", (stat & 0x1f000000) >> 24);
|
||||
pr_cont("/GPC%d/", (stat & 0x1f000000) >> 24);
|
||||
nouveau_enum_print(nve0_fifo_fault_gpcclient, client);
|
||||
}
|
||||
printk(" on channel 0x%010llx\n", (u64)inst << 12);
|
||||
|
||||
if (en && en->data2) {
|
||||
engine = nouveau_engine(priv, en->data2);
|
||||
if (engine)
|
||||
engctx = nouveau_engctx_get(engine, inst);
|
||||
|
||||
}
|
||||
|
||||
pr_cont(" on channel 0x%010llx [%s]\n", (u64)inst << 12,
|
||||
nouveau_client_name(engctx));
|
||||
|
||||
nouveau_engctx_put(engctx);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -480,10 +496,12 @@ nve0_fifo_isr_subfifo_intr(struct nve0_fifo_priv *priv, int unit)
|
||||
if (show) {
|
||||
nv_error(priv, "SUBFIFO%d:", unit);
|
||||
nouveau_bitfield_print(nve0_fifo_subfifo_intr, show);
|
||||
printk("\n");
|
||||
nv_error(priv, "SUBFIFO%d: ch %d subc %d mthd 0x%04x "
|
||||
"data 0x%08x\n",
|
||||
unit, chid, subc, mthd, data);
|
||||
pr_cont("\n");
|
||||
nv_error(priv,
|
||||
"SUBFIFO%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
|
||||
unit, chid,
|
||||
nouveau_client_name_for_fifo_chid(&priv->base, chid),
|
||||
subc, mthd, data);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
|
||||
@ -537,6 +555,12 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
|
||||
stat &= ~0x40000000;
|
||||
}
|
||||
|
||||
if (stat & 0x80000000) {
|
||||
nouveau_event_trigger(priv->base.uevent, 0);
|
||||
nv_wr32(priv, 0x002100, 0x80000000);
|
||||
stat &= ~0x80000000;
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
nv_fatal(priv, "unhandled status 0x%08x\n", stat);
|
||||
nv_wr32(priv, 0x002100, stat);
|
||||
@ -544,6 +568,20 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nve0_fifo_uevent_enable(struct nouveau_event *event, int index)
|
||||
{
|
||||
struct nve0_fifo_priv *priv = event->priv;
|
||||
nv_mask(priv, 0x002140, 0x80000000, 0x80000000);
|
||||
}
|
||||
|
||||
static void
|
||||
nve0_fifo_uevent_disable(struct nouveau_event *event, int index)
|
||||
{
|
||||
struct nve0_fifo_priv *priv = event->priv;
|
||||
nv_mask(priv, 0x002140, 0x80000000, 0x00000000);
|
||||
}
|
||||
|
||||
static int
|
||||
nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
@ -567,6 +605,10 @@ nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->base.uevent->enable = nve0_fifo_uevent_enable;
|
||||
priv->base.uevent->disable = nve0_fifo_uevent_disable;
|
||||
priv->base.uevent->priv = priv;
|
||||
|
||||
nv_subdev(priv)->unit = 0x00000100;
|
||||
nv_subdev(priv)->intr = nve0_fifo_intr;
|
||||
nv_engine(priv)->cclass = &nve0_fifo_cclass;
|
||||
@ -617,7 +659,7 @@ nve0_fifo_init(struct nouveau_object *object)
|
||||
|
||||
nv_wr32(priv, 0x002a00, 0xffffffff);
|
||||
nv_wr32(priv, 0x002100, 0xffffffff);
|
||||
nv_wr32(priv, 0x002140, 0xbfffffff);
|
||||
nv_wr32(priv, 0x002140, 0x3fffffff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <core/client.h>
|
||||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/handle.h>
|
||||
@ -1297,16 +1298,17 @@ nv04_graph_intr(struct nouveau_subdev *subdev)
|
||||
nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
|
||||
|
||||
if (show) {
|
||||
nv_error(priv, "");
|
||||
nv_error(priv, "%s", "");
|
||||
nouveau_bitfield_print(nv04_graph_intr_name, show);
|
||||
printk(" nsource:");
|
||||
pr_cont(" nsource:");
|
||||
nouveau_bitfield_print(nv04_graph_nsource, nsource);
|
||||
printk(" nstatus:");
|
||||
pr_cont(" nstatus:");
|
||||
nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
|
||||
printk("\n");
|
||||
nv_error(priv, "ch %d/%d class 0x%04x "
|
||||
"mthd 0x%04x data 0x%08x\n",
|
||||
chid, subc, class, mthd, data);
|
||||
pr_cont("\n");
|
||||
nv_error(priv,
|
||||
"ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
|
||||
chid, nouveau_client_name(chan), subc, class, mthd,
|
||||
data);
|
||||
}
|
||||
|
||||
nouveau_namedb_put(handle);
|
||||
|
@ -22,6 +22,7 @@
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <core/client.h>
|
||||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/handle.h>
|
||||
@ -1193,16 +1194,17 @@ nv10_graph_intr(struct nouveau_subdev *subdev)
|
||||
nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
|
||||
|
||||
if (show) {
|
||||
nv_error(priv, "");
|
||||
nv_error(priv, "%s", "");
|
||||
nouveau_bitfield_print(nv10_graph_intr_name, show);
|
||||
printk(" nsource:");
|
||||
pr_cont(" nsource:");
|
||||
nouveau_bitfield_print(nv04_graph_nsource, nsource);
|
||||
printk(" nstatus:");
|
||||
pr_cont(" nstatus:");
|
||||
nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
|
||||
printk("\n");
|
||||
nv_error(priv, "ch %d/%d class 0x%04x "
|
||||
"mthd 0x%04x data 0x%08x\n",
|
||||
chid, subc, class, mthd, data);
|
||||
pr_cont("\n");
|
||||
nv_error(priv,
|
||||
"ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
|
||||
chid, nouveau_client_name(chan), subc, class, mthd,
|
||||
data);
|
||||
}
|
||||
|
||||
nouveau_namedb_put(handle);
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <core/client.h>
|
||||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
@ -224,15 +225,17 @@ nv20_graph_intr(struct nouveau_subdev *subdev)
|
||||
nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
|
||||
|
||||
if (show) {
|
||||
nv_error(priv, "");
|
||||
nv_error(priv, "%s", "");
|
||||
nouveau_bitfield_print(nv10_graph_intr_name, show);
|
||||
printk(" nsource:");
|
||||
pr_cont(" nsource:");
|
||||
nouveau_bitfield_print(nv04_graph_nsource, nsource);
|
||||
printk(" nstatus:");
|
||||
pr_cont(" nstatus:");
|
||||
nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
|
||||
printk("\n");
|
||||
nv_error(priv, "ch %d/%d class 0x%04x mthd 0x%04x data 0x%08x\n",
|
||||
chid, subc, class, mthd, data);
|
||||
pr_cont("\n");
|
||||
nv_error(priv,
|
||||
"ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
|
||||
chid, nouveau_client_name(engctx), subc, class, mthd,
|
||||
data);
|
||||
}
|
||||
|
||||
nouveau_engctx_put(engctx);
|
||||
|
@ -22,6 +22,7 @@
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/client.h>
|
||||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/handle.h>
|
||||
@ -321,16 +322,17 @@ nv40_graph_intr(struct nouveau_subdev *subdev)
|
||||
nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
|
||||
|
||||
if (show) {
|
||||
nv_error(priv, "");
|
||||
nv_error(priv, "%s", "");
|
||||
nouveau_bitfield_print(nv10_graph_intr_name, show);
|
||||
printk(" nsource:");
|
||||
pr_cont(" nsource:");
|
||||
nouveau_bitfield_print(nv04_graph_nsource, nsource);
|
||||
printk(" nstatus:");
|
||||
pr_cont(" nstatus:");
|
||||
nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
|
||||
printk("\n");
|
||||
nv_error(priv, "ch %d [0x%08x] subc %d class 0x%04x "
|
||||
"mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst << 4, subc, class, mthd, data);
|
||||
pr_cont("\n");
|
||||
nv_error(priv,
|
||||
"ch %d [0x%08x %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst << 4, nouveau_client_name(engctx), subc,
|
||||
class, mthd, data);
|
||||
}
|
||||
|
||||
nouveau_engctx_put(engctx);
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/client.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/enum.h>
|
||||
@ -418,7 +419,7 @@ nv50_priv_mp_trap(struct nv50_graph_priv *priv, int tpid, int display)
|
||||
nv_error(priv, "TRAP_MP_EXEC - "
|
||||
"TP %d MP %d: ", tpid, i);
|
||||
nouveau_enum_print(nv50_mp_exec_error_names, status);
|
||||
printk(" at %06x warp %d, opcode %08x %08x\n",
|
||||
pr_cont(" at %06x warp %d, opcode %08x %08x\n",
|
||||
pc&0xffffff, pc >> 24,
|
||||
oplow, ophigh);
|
||||
}
|
||||
@ -532,7 +533,7 @@ nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old,
|
||||
|
||||
static int
|
||||
nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display,
|
||||
int chid, u64 inst)
|
||||
int chid, u64 inst, struct nouveau_object *engctx)
|
||||
{
|
||||
u32 status = nv_rd32(priv, 0x400108);
|
||||
u32 ustatus;
|
||||
@ -565,12 +566,11 @@ nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display,
|
||||
|
||||
nv_error(priv, "TRAP DISPATCH_FAULT\n");
|
||||
if (display && (addr & 0x80000000)) {
|
||||
nv_error(priv, "ch %d [0x%010llx] "
|
||||
"subc %d class 0x%04x mthd 0x%04x "
|
||||
"data 0x%08x%08x "
|
||||
"400808 0x%08x 400848 0x%08x\n",
|
||||
chid, inst, subc, class, mthd, datah,
|
||||
datal, addr, r848);
|
||||
nv_error(priv,
|
||||
"ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x%08x 400808 0x%08x 400848 0x%08x\n",
|
||||
chid, inst,
|
||||
nouveau_client_name(engctx), subc,
|
||||
class, mthd, datah, datal, addr, r848);
|
||||
} else
|
||||
if (display) {
|
||||
nv_error(priv, "no stuck command?\n");
|
||||
@ -591,11 +591,11 @@ nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display,
|
||||
|
||||
nv_error(priv, "TRAP DISPATCH_QUERY\n");
|
||||
if (display && (addr & 0x80000000)) {
|
||||
nv_error(priv, "ch %d [0x%010llx] "
|
||||
"subc %d class 0x%04x mthd 0x%04x "
|
||||
"data 0x%08x 40084c 0x%08x\n",
|
||||
chid, inst, subc, class, mthd,
|
||||
data, addr);
|
||||
nv_error(priv,
|
||||
"ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x 40084c 0x%08x\n",
|
||||
chid, inst,
|
||||
nouveau_client_name(engctx), subc,
|
||||
class, mthd, data, addr);
|
||||
} else
|
||||
if (display) {
|
||||
nv_error(priv, "no stuck command?\n");
|
||||
@ -623,7 +623,7 @@ nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display,
|
||||
if (display) {
|
||||
nv_error(priv, "TRAP_M2MF");
|
||||
nouveau_bitfield_print(nv50_graph_trap_m2mf, ustatus);
|
||||
printk("\n");
|
||||
pr_cont("\n");
|
||||
nv_error(priv, "TRAP_M2MF %08x %08x %08x %08x\n",
|
||||
nv_rd32(priv, 0x406804), nv_rd32(priv, 0x406808),
|
||||
nv_rd32(priv, 0x40680c), nv_rd32(priv, 0x406810));
|
||||
@ -644,7 +644,7 @@ nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display,
|
||||
if (display) {
|
||||
nv_error(priv, "TRAP_VFETCH");
|
||||
nouveau_bitfield_print(nv50_graph_trap_vfetch, ustatus);
|
||||
printk("\n");
|
||||
pr_cont("\n");
|
||||
nv_error(priv, "TRAP_VFETCH %08x %08x %08x %08x\n",
|
||||
nv_rd32(priv, 0x400c00), nv_rd32(priv, 0x400c08),
|
||||
nv_rd32(priv, 0x400c0c), nv_rd32(priv, 0x400c10));
|
||||
@ -661,7 +661,7 @@ nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display,
|
||||
if (display) {
|
||||
nv_error(priv, "TRAP_STRMOUT");
|
||||
nouveau_bitfield_print(nv50_graph_trap_strmout, ustatus);
|
||||
printk("\n");
|
||||
pr_cont("\n");
|
||||
nv_error(priv, "TRAP_STRMOUT %08x %08x %08x %08x\n",
|
||||
nv_rd32(priv, 0x401804), nv_rd32(priv, 0x401808),
|
||||
nv_rd32(priv, 0x40180c), nv_rd32(priv, 0x401810));
|
||||
@ -682,7 +682,7 @@ nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display,
|
||||
if (display) {
|
||||
nv_error(priv, "TRAP_CCACHE");
|
||||
nouveau_bitfield_print(nv50_graph_trap_ccache, ustatus);
|
||||
printk("\n");
|
||||
pr_cont("\n");
|
||||
nv_error(priv, "TRAP_CCACHE %08x %08x %08x %08x"
|
||||
" %08x %08x %08x\n",
|
||||
nv_rd32(priv, 0x405000), nv_rd32(priv, 0x405004),
|
||||
@ -774,11 +774,12 @@ nv50_graph_intr(struct nouveau_subdev *subdev)
|
||||
u32 ecode = nv_rd32(priv, 0x400110);
|
||||
nv_error(priv, "DATA_ERROR ");
|
||||
nouveau_enum_print(nv50_data_error_names, ecode);
|
||||
printk("\n");
|
||||
pr_cont("\n");
|
||||
}
|
||||
|
||||
if (stat & 0x00200000) {
|
||||
if (!nv50_graph_trap_handler(priv, show, chid, (u64)inst << 12))
|
||||
if (!nv50_graph_trap_handler(priv, show, chid, (u64)inst << 12,
|
||||
engctx))
|
||||
show &= ~0x00200000;
|
||||
}
|
||||
|
||||
@ -786,12 +787,13 @@ nv50_graph_intr(struct nouveau_subdev *subdev)
|
||||
nv_wr32(priv, 0x400500, 0x00010001);
|
||||
|
||||
if (show) {
|
||||
nv_error(priv, "");
|
||||
nv_error(priv, "%s", "");
|
||||
nouveau_bitfield_print(nv50_graph_intr_name, show);
|
||||
printk("\n");
|
||||
nv_error(priv, "ch %d [0x%010llx] subc %d class 0x%04x "
|
||||
"mthd 0x%04x data 0x%08x\n",
|
||||
chid, (u64)inst << 12, subc, class, mthd, data);
|
||||
pr_cont("\n");
|
||||
nv_error(priv,
|
||||
"ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
|
||||
chid, (u64)inst << 12, nouveau_client_name(engctx),
|
||||
subc, class, mthd, data);
|
||||
}
|
||||
|
||||
if (nv_rd32(priv, 0x400824) & (1 << 31))
|
||||
@ -907,9 +909,8 @@ nv50_graph_init(struct nouveau_object *object)
|
||||
nv_wr32(priv, 0x400828, 0x00000000);
|
||||
nv_wr32(priv, 0x40082c, 0x00000000);
|
||||
nv_wr32(priv, 0x400830, 0x00000000);
|
||||
nv_wr32(priv, 0x400724, 0x00000000);
|
||||
nv_wr32(priv, 0x40032c, 0x00000000);
|
||||
nv_wr32(priv, 0x400320, 4); /* CTXCTL_CMD = NEWCTXDMA */
|
||||
nv_wr32(priv, 0x400330, 0x00000000);
|
||||
|
||||
/* some unknown zcull magic */
|
||||
switch (nv_device(priv)->chipset & 0xf0) {
|
||||
|
@ -433,10 +433,10 @@ nvc0_graph_intr(struct nouveau_subdev *subdev)
|
||||
if (stat & 0x00000010) {
|
||||
handle = nouveau_handle_get_class(engctx, class);
|
||||
if (!handle || nv_call(handle->object, mthd, data)) {
|
||||
nv_error(priv, "ILLEGAL_MTHD ch %d [0x%010llx] "
|
||||
"subc %d class 0x%04x mthd 0x%04x "
|
||||
"data 0x%08x\n",
|
||||
chid, inst << 12, subc, class, mthd, data);
|
||||
nv_error(priv,
|
||||
"ILLEGAL_MTHD ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst << 12, nouveau_client_name(engctx),
|
||||
subc, class, mthd, data);
|
||||
}
|
||||
nouveau_handle_put(handle);
|
||||
nv_wr32(priv, 0x400100, 0x00000010);
|
||||
@ -444,9 +444,10 @@ nvc0_graph_intr(struct nouveau_subdev *subdev)
|
||||
}
|
||||
|
||||
if (stat & 0x00000020) {
|
||||
nv_error(priv, "ILLEGAL_CLASS ch %d [0x%010llx] subc %d "
|
||||
"class 0x%04x mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst << 12, subc, class, mthd, data);
|
||||
nv_error(priv,
|
||||
"ILLEGAL_CLASS ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst << 12, nouveau_client_name(engctx), subc,
|
||||
class, mthd, data);
|
||||
nv_wr32(priv, 0x400100, 0x00000020);
|
||||
stat &= ~0x00000020;
|
||||
}
|
||||
@ -454,15 +455,16 @@ nvc0_graph_intr(struct nouveau_subdev *subdev)
|
||||
if (stat & 0x00100000) {
|
||||
nv_error(priv, "DATA_ERROR [");
|
||||
nouveau_enum_print(nv50_data_error_names, code);
|
||||
printk("] ch %d [0x%010llx] subc %d class 0x%04x "
|
||||
"mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst << 12, subc, class, mthd, data);
|
||||
pr_cont("] ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst << 12, nouveau_client_name(engctx), subc,
|
||||
class, mthd, data);
|
||||
nv_wr32(priv, 0x400100, 0x00100000);
|
||||
stat &= ~0x00100000;
|
||||
}
|
||||
|
||||
if (stat & 0x00200000) {
|
||||
nv_error(priv, "TRAP ch %d [0x%010llx]\n", chid, inst << 12);
|
||||
nv_error(priv, "TRAP ch %d [0x%010llx %s]\n", chid, inst << 12,
|
||||
nouveau_client_name(engctx));
|
||||
nvc0_graph_trap_intr(priv);
|
||||
nv_wr32(priv, 0x400100, 0x00200000);
|
||||
stat &= ~0x00200000;
|
||||
@ -611,10 +613,8 @@ nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
static void
|
||||
nvc0_graph_dtor_fw(struct nvc0_graph_fuc *fuc)
|
||||
{
|
||||
if (fuc->data) {
|
||||
kfree(fuc->data);
|
||||
fuc->data = NULL;
|
||||
}
|
||||
kfree(fuc->data);
|
||||
fuc->data = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
@ -622,8 +622,7 @@ nvc0_graph_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nvc0_graph_priv *priv = (void *)object;
|
||||
|
||||
if (priv->data)
|
||||
kfree(priv->data);
|
||||
kfree(priv->data);
|
||||
|
||||
nvc0_graph_dtor_fw(&priv->fuc409c);
|
||||
nvc0_graph_dtor_fw(&priv->fuc409d);
|
||||
|
@ -78,15 +78,16 @@ nve0_graph_ctxctl_isr(struct nvc0_graph_priv *priv)
|
||||
}
|
||||
|
||||
static void
|
||||
nve0_graph_trap_isr(struct nvc0_graph_priv *priv, int chid, u64 inst)
|
||||
nve0_graph_trap_isr(struct nvc0_graph_priv *priv, int chid, u64 inst,
|
||||
struct nouveau_object *engctx)
|
||||
{
|
||||
u32 trap = nv_rd32(priv, 0x400108);
|
||||
int rop;
|
||||
|
||||
if (trap & 0x00000001) {
|
||||
u32 stat = nv_rd32(priv, 0x404000);
|
||||
nv_error(priv, "DISPATCH ch %d [0x%010llx] 0x%08x\n",
|
||||
chid, inst, stat);
|
||||
nv_error(priv, "DISPATCH ch %d [0x%010llx %s] 0x%08x\n",
|
||||
chid, inst, nouveau_client_name(engctx), stat);
|
||||
nv_wr32(priv, 0x404000, 0xc0000000);
|
||||
nv_wr32(priv, 0x400108, 0x00000001);
|
||||
trap &= ~0x00000001;
|
||||
@ -94,8 +95,8 @@ nve0_graph_trap_isr(struct nvc0_graph_priv *priv, int chid, u64 inst)
|
||||
|
||||
if (trap & 0x00000010) {
|
||||
u32 stat = nv_rd32(priv, 0x405840);
|
||||
nv_error(priv, "SHADER ch %d [0x%010llx] 0x%08x\n",
|
||||
chid, inst, stat);
|
||||
nv_error(priv, "SHADER ch %d [0x%010llx %s] 0x%08x\n",
|
||||
chid, inst, nouveau_client_name(engctx), stat);
|
||||
nv_wr32(priv, 0x405840, 0xc0000000);
|
||||
nv_wr32(priv, 0x400108, 0x00000010);
|
||||
trap &= ~0x00000010;
|
||||
@ -105,8 +106,10 @@ nve0_graph_trap_isr(struct nvc0_graph_priv *priv, int chid, u64 inst)
|
||||
for (rop = 0; rop < priv->rop_nr; rop++) {
|
||||
u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070));
|
||||
u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144));
|
||||
nv_error(priv, "ROP%d ch %d [0x%010llx] 0x%08x 0x%08x\n",
|
||||
rop, chid, inst, statz, statc);
|
||||
nv_error(priv,
|
||||
"ROP%d ch %d [0x%010llx %s] 0x%08x 0x%08x\n",
|
||||
rop, chid, inst, nouveau_client_name(engctx),
|
||||
statz, statc);
|
||||
nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
|
||||
nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
|
||||
}
|
||||
@ -115,8 +118,8 @@ nve0_graph_trap_isr(struct nvc0_graph_priv *priv, int chid, u64 inst)
|
||||
}
|
||||
|
||||
if (trap) {
|
||||
nv_error(priv, "TRAP ch %d [0x%010llx] 0x%08x\n",
|
||||
chid, inst, trap);
|
||||
nv_error(priv, "TRAP ch %d [0x%010llx %s] 0x%08x\n",
|
||||
chid, inst, nouveau_client_name(engctx), trap);
|
||||
nv_wr32(priv, 0x400108, trap);
|
||||
}
|
||||
}
|
||||
@ -145,10 +148,10 @@ nve0_graph_intr(struct nouveau_subdev *subdev)
|
||||
if (stat & 0x00000010) {
|
||||
handle = nouveau_handle_get_class(engctx, class);
|
||||
if (!handle || nv_call(handle->object, mthd, data)) {
|
||||
nv_error(priv, "ILLEGAL_MTHD ch %d [0x%010llx] "
|
||||
"subc %d class 0x%04x mthd 0x%04x "
|
||||
"data 0x%08x\n",
|
||||
chid, inst, subc, class, mthd, data);
|
||||
nv_error(priv,
|
||||
"ILLEGAL_MTHD ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst, nouveau_client_name(engctx), subc,
|
||||
class, mthd, data);
|
||||
}
|
||||
nouveau_handle_put(handle);
|
||||
nv_wr32(priv, 0x400100, 0x00000010);
|
||||
@ -156,9 +159,10 @@ nve0_graph_intr(struct nouveau_subdev *subdev)
|
||||
}
|
||||
|
||||
if (stat & 0x00000020) {
|
||||
nv_error(priv, "ILLEGAL_CLASS ch %d [0x%010llx] subc %d "
|
||||
"class 0x%04x mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst, subc, class, mthd, data);
|
||||
nv_error(priv,
|
||||
"ILLEGAL_CLASS ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst, nouveau_client_name(engctx), subc, class,
|
||||
mthd, data);
|
||||
nv_wr32(priv, 0x400100, 0x00000020);
|
||||
stat &= ~0x00000020;
|
||||
}
|
||||
@ -166,15 +170,15 @@ nve0_graph_intr(struct nouveau_subdev *subdev)
|
||||
if (stat & 0x00100000) {
|
||||
nv_error(priv, "DATA_ERROR [");
|
||||
nouveau_enum_print(nv50_data_error_names, code);
|
||||
printk("] ch %d [0x%010llx] subc %d class 0x%04x "
|
||||
"mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst, subc, class, mthd, data);
|
||||
pr_cont("] ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst, nouveau_client_name(engctx), subc, class,
|
||||
mthd, data);
|
||||
nv_wr32(priv, 0x400100, 0x00100000);
|
||||
stat &= ~0x00100000;
|
||||
}
|
||||
|
||||
if (stat & 0x00200000) {
|
||||
nve0_graph_trap_isr(priv, chid, inst);
|
||||
nve0_graph_trap_isr(priv, chid, inst, engctx);
|
||||
nv_wr32(priv, 0x400100, 0x00200000);
|
||||
stat &= ~0x00200000;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/client.h>
|
||||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
@ -231,8 +232,10 @@ nv31_mpeg_intr(struct nouveau_subdev *subdev)
|
||||
nv_wr32(priv, 0x00b230, 0x00000001);
|
||||
|
||||
if (show) {
|
||||
nv_error(priv, "ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
|
||||
chid, inst << 4, stat, type, mthd, data);
|
||||
nv_error(priv,
|
||||
"ch %d [0x%08x %s] 0x%08x 0x%08x 0x%08x 0x%08x\n",
|
||||
chid, inst << 4, nouveau_client_name(engctx), stat,
|
||||
type, mthd, data);
|
||||
}
|
||||
|
||||
nouveau_engctx_put(engctx);
|
||||
|
@ -28,6 +28,9 @@
|
||||
#include <core/namedb.h>
|
||||
#include <core/handle.h>
|
||||
#include <core/gpuobj.h>
|
||||
#include <core/event.h>
|
||||
|
||||
#include <subdev/bar.h>
|
||||
|
||||
#include <engine/software.h>
|
||||
#include <engine/disp.h>
|
||||
@ -90,18 +93,11 @@ nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
|
||||
{
|
||||
struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
|
||||
struct nouveau_disp *disp = nouveau_disp(object);
|
||||
unsigned long flags;
|
||||
u32 crtc = *(u32 *)args;
|
||||
|
||||
if (crtc > 1)
|
||||
return -EINVAL;
|
||||
|
||||
disp->vblank.get(disp->vblank.data, crtc);
|
||||
|
||||
spin_lock_irqsave(&disp->vblank.lock, flags);
|
||||
list_add(&chan->base.vblank.head, &disp->vblank.list);
|
||||
chan->base.vblank.crtc = crtc;
|
||||
spin_unlock_irqrestore(&disp->vblank.lock, flags);
|
||||
nouveau_event_get(disp->vblank, crtc, &chan->base.vblank.event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -135,6 +131,29 @@ nv50_software_sclass[] = {
|
||||
* software context
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nv50_software_vblsem_release(struct nouveau_eventh *event, int head)
|
||||
{
|
||||
struct nouveau_software_chan *chan =
|
||||
container_of(event, struct nouveau_software_chan, vblank.event);
|
||||
struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
|
||||
struct nouveau_bar *bar = nouveau_bar(priv);
|
||||
|
||||
nv_wr32(priv, 0x001704, chan->vblank.channel);
|
||||
nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
|
||||
bar->flush(bar);
|
||||
|
||||
if (nv_device(priv)->chipset == 0x50) {
|
||||
nv_wr32(priv, 0x001570, chan->vblank.offset);
|
||||
nv_wr32(priv, 0x001574, chan->vblank.value);
|
||||
} else {
|
||||
nv_wr32(priv, 0x060010, chan->vblank.offset);
|
||||
nv_wr32(priv, 0x060014, chan->vblank.value);
|
||||
}
|
||||
|
||||
return NVKM_EVENT_DROP;
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_software_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
@ -150,6 +169,7 @@ nv50_software_context_ctor(struct nouveau_object *parent,
|
||||
return ret;
|
||||
|
||||
chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
|
||||
chan->base.vblank.event.func = nv50_software_vblsem_release;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -170,8 +190,8 @@ nv50_software_cclass = {
|
||||
|
||||
static int
|
||||
nv50_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv50_software_priv *priv;
|
||||
int ret;
|
||||
|
@ -25,6 +25,9 @@
|
||||
#include <core/os.h>
|
||||
#include <core/class.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/event.h>
|
||||
|
||||
#include <subdev/bar.h>
|
||||
|
||||
#include <engine/software.h>
|
||||
#include <engine/disp.h>
|
||||
@ -72,18 +75,12 @@ nvc0_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
|
||||
{
|
||||
struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent);
|
||||
struct nouveau_disp *disp = nouveau_disp(object);
|
||||
unsigned long flags;
|
||||
u32 crtc = *(u32 *)args;
|
||||
|
||||
if ((nv_device(object)->card_type < NV_E0 && crtc > 1) || crtc > 3)
|
||||
return -EINVAL;
|
||||
|
||||
disp->vblank.get(disp->vblank.data, crtc);
|
||||
|
||||
spin_lock_irqsave(&disp->vblank.lock, flags);
|
||||
list_add(&chan->base.vblank.head, &disp->vblank.list);
|
||||
chan->base.vblank.crtc = crtc;
|
||||
spin_unlock_irqrestore(&disp->vblank.lock, flags);
|
||||
nouveau_event_get(disp->vblank, crtc, &chan->base.vblank.event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -117,6 +114,23 @@ nvc0_software_sclass[] = {
|
||||
* software context
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nvc0_software_vblsem_release(struct nouveau_eventh *event, int head)
|
||||
{
|
||||
struct nouveau_software_chan *chan =
|
||||
container_of(event, struct nouveau_software_chan, vblank.event);
|
||||
struct nvc0_software_priv *priv = (void *)nv_object(chan)->engine;
|
||||
struct nouveau_bar *bar = nouveau_bar(priv);
|
||||
|
||||
nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
|
||||
bar->flush(bar);
|
||||
nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset));
|
||||
nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset));
|
||||
nv_wr32(priv, 0x060014, chan->vblank.value);
|
||||
|
||||
return NVKM_EVENT_DROP;
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_software_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
@ -132,6 +146,7 @@ nvc0_software_context_ctor(struct nouveau_object *parent,
|
||||
return ret;
|
||||
|
||||
chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
|
||||
chan->base.vblank.event.func = nvc0_software_vblsem_release;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -154,6 +154,14 @@ struct nve0_channel_ind_class {
|
||||
u32 engine;
|
||||
};
|
||||
|
||||
/* 0046: NV04_DISP
|
||||
*/
|
||||
|
||||
#define NV04_DISP_CLASS 0x00000046
|
||||
|
||||
struct nv04_display_class {
|
||||
};
|
||||
|
||||
/* 5070: NV50_DISP
|
||||
* 8270: NV84_DISP
|
||||
* 8370: NVA0_DISP
|
||||
@ -190,25 +198,6 @@ struct nve0_channel_ind_class {
|
||||
#define NV84_DISP_SOR_HDMI_PWR_REKEY 0x0000007f
|
||||
#define NV50_DISP_SOR_LVDS_SCRIPT 0x00013000
|
||||
#define NV50_DISP_SOR_LVDS_SCRIPT_ID 0x0000ffff
|
||||
#define NV94_DISP_SOR_DP_TRAIN 0x00016000
|
||||
#define NV94_DISP_SOR_DP_TRAIN_OP 0xf0000000
|
||||
#define NV94_DISP_SOR_DP_TRAIN_OP_PATTERN 0x00000000
|
||||
#define NV94_DISP_SOR_DP_TRAIN_OP_INIT 0x10000000
|
||||
#define NV94_DISP_SOR_DP_TRAIN_OP_FINI 0x20000000
|
||||
#define NV94_DISP_SOR_DP_TRAIN_INIT_SPREAD 0x00000001
|
||||
#define NV94_DISP_SOR_DP_TRAIN_INIT_SPREAD_OFF 0x00000000
|
||||
#define NV94_DISP_SOR_DP_TRAIN_INIT_SPREAD_ON 0x00000001
|
||||
#define NV94_DISP_SOR_DP_TRAIN_PATTERN 0x00000003
|
||||
#define NV94_DISP_SOR_DP_TRAIN_PATTERN_DISABLED 0x00000000
|
||||
#define NV94_DISP_SOR_DP_LNKCTL 0x00016040
|
||||
#define NV94_DISP_SOR_DP_LNKCTL_FRAME 0x80000000
|
||||
#define NV94_DISP_SOR_DP_LNKCTL_FRAME_STD 0x00000000
|
||||
#define NV94_DISP_SOR_DP_LNKCTL_FRAME_ENH 0x80000000
|
||||
#define NV94_DISP_SOR_DP_LNKCTL_WIDTH 0x00001f00
|
||||
#define NV94_DISP_SOR_DP_LNKCTL_COUNT 0x00000007
|
||||
#define NV94_DISP_SOR_DP_DRVCTL(l) ((l) * 0x40 + 0x00016100)
|
||||
#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
|
||||
@ -230,6 +219,23 @@ struct nve0_channel_ind_class {
|
||||
#define NV50_DISP_DAC_LOAD 0x0002000c
|
||||
#define NV50_DISP_DAC_LOAD_VALUE 0x00000007
|
||||
|
||||
#define NV50_DISP_PIOR_MTHD 0x00030000
|
||||
#define NV50_DISP_PIOR_MTHD_TYPE 0x0000f000
|
||||
#define NV50_DISP_PIOR_MTHD_OR 0x00000003
|
||||
|
||||
#define NV50_DISP_PIOR_PWR 0x00030000
|
||||
#define NV50_DISP_PIOR_PWR_STATE 0x00000001
|
||||
#define NV50_DISP_PIOR_PWR_STATE_ON 0x00000001
|
||||
#define NV50_DISP_PIOR_PWR_STATE_OFF 0x00000000
|
||||
#define NV50_DISP_PIOR_TMDS_PWR 0x00032000
|
||||
#define NV50_DISP_PIOR_TMDS_PWR_STATE 0x00000001
|
||||
#define NV50_DISP_PIOR_TMDS_PWR_STATE_ON 0x00000001
|
||||
#define NV50_DISP_PIOR_TMDS_PWR_STATE_OFF 0x00000000
|
||||
#define NV50_DISP_PIOR_DP_PWR 0x00036000
|
||||
#define NV50_DISP_PIOR_DP_PWR_STATE 0x00000001
|
||||
#define NV50_DISP_PIOR_DP_PWR_STATE_ON 0x00000001
|
||||
#define NV50_DISP_PIOR_DP_PWR_STATE_OFF 0x00000000
|
||||
|
||||
struct nv50_display_class {
|
||||
};
|
||||
|
||||
|
@ -7,7 +7,7 @@ struct nouveau_client {
|
||||
struct nouveau_namedb base;
|
||||
struct nouveau_handle *root;
|
||||
struct nouveau_object *device;
|
||||
char name[16];
|
||||
char name[32];
|
||||
u32 debug;
|
||||
struct nouveau_vm *vm;
|
||||
};
|
||||
@ -41,5 +41,6 @@ int nouveau_client_create_(const char *name, u64 device, const char *cfg,
|
||||
|
||||
int nouveau_client_init(struct nouveau_client *);
|
||||
int nouveau_client_fini(struct nouveau_client *, bool suspend);
|
||||
const char *nouveau_client_name(void *obj);
|
||||
|
||||
#endif
|
||||
|
@ -26,6 +26,7 @@ enum nv_subdev_type {
|
||||
*/
|
||||
NVDEV_SUBDEV_MXM,
|
||||
NVDEV_SUBDEV_MC,
|
||||
NVDEV_SUBDEV_BUS,
|
||||
NVDEV_SUBDEV_TIMER,
|
||||
NVDEV_SUBDEV_FB,
|
||||
NVDEV_SUBDEV_LTCG,
|
||||
|
@ -5,12 +5,13 @@ struct nouveau_enum {
|
||||
u32 value;
|
||||
const char *name;
|
||||
const void *data;
|
||||
u32 data2;
|
||||
};
|
||||
|
||||
const struct nouveau_enum *
|
||||
nouveau_enum_find(const struct nouveau_enum *, u32 value);
|
||||
|
||||
void
|
||||
const struct nouveau_enum *
|
||||
nouveau_enum_print(const struct nouveau_enum *en, u32 value);
|
||||
|
||||
struct nouveau_bitfield {
|
||||
|
36
drivers/gpu/drm/nouveau/core/include/core/event.h
Normal file
36
drivers/gpu/drm/nouveau/core/include/core/event.h
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef __NVKM_EVENT_H__
|
||||
#define __NVKM_EVENT_H__
|
||||
|
||||
/* return codes from event handlers */
|
||||
#define NVKM_EVENT_DROP 0
|
||||
#define NVKM_EVENT_KEEP 1
|
||||
|
||||
struct nouveau_eventh {
|
||||
struct list_head head;
|
||||
int (*func)(struct nouveau_eventh *, int index);
|
||||
};
|
||||
|
||||
struct nouveau_event {
|
||||
spinlock_t lock;
|
||||
|
||||
void *priv;
|
||||
void (*enable)(struct nouveau_event *, int index);
|
||||
void (*disable)(struct nouveau_event *, int index);
|
||||
|
||||
int index_nr;
|
||||
struct {
|
||||
struct list_head list;
|
||||
int refs;
|
||||
} index[];
|
||||
};
|
||||
|
||||
int nouveau_event_create(int index_nr, struct nouveau_event **);
|
||||
void nouveau_event_destroy(struct nouveau_event **);
|
||||
void nouveau_event_trigger(struct nouveau_event *, int index);
|
||||
|
||||
void nouveau_event_get(struct nouveau_event *, int index,
|
||||
struct nouveau_eventh *);
|
||||
void nouveau_event_put(struct nouveau_event *, int index,
|
||||
struct nouveau_eventh *);
|
||||
|
||||
#endif
|
@ -133,7 +133,7 @@ static inline u8
|
||||
nv_ro08(void *obj, u64 addr)
|
||||
{
|
||||
u8 data = nv_ofuncs(obj)->rd08(obj, addr);
|
||||
nv_spam(obj, "nv_ro08 0x%08x 0x%02x\n", addr, data);
|
||||
nv_spam(obj, "nv_ro08 0x%08llx 0x%02x\n", addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -141,7 +141,7 @@ static inline u16
|
||||
nv_ro16(void *obj, u64 addr)
|
||||
{
|
||||
u16 data = nv_ofuncs(obj)->rd16(obj, addr);
|
||||
nv_spam(obj, "nv_ro16 0x%08x 0x%04x\n", addr, data);
|
||||
nv_spam(obj, "nv_ro16 0x%08llx 0x%04x\n", addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -149,28 +149,28 @@ static inline u32
|
||||
nv_ro32(void *obj, u64 addr)
|
||||
{
|
||||
u32 data = nv_ofuncs(obj)->rd32(obj, addr);
|
||||
nv_spam(obj, "nv_ro32 0x%08x 0x%08x\n", addr, data);
|
||||
nv_spam(obj, "nv_ro32 0x%08llx 0x%08x\n", addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline void
|
||||
nv_wo08(void *obj, u64 addr, u8 data)
|
||||
{
|
||||
nv_spam(obj, "nv_wo08 0x%08x 0x%02x\n", addr, data);
|
||||
nv_spam(obj, "nv_wo08 0x%08llx 0x%02x\n", addr, data);
|
||||
nv_ofuncs(obj)->wr08(obj, addr, data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
nv_wo16(void *obj, u64 addr, u16 data)
|
||||
{
|
||||
nv_spam(obj, "nv_wo16 0x%08x 0x%04x\n", addr, data);
|
||||
nv_spam(obj, "nv_wo16 0x%08llx 0x%04x\n", addr, data);
|
||||
nv_ofuncs(obj)->wr16(obj, addr, data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
nv_wo32(void *obj, u64 addr, u32 data)
|
||||
{
|
||||
nv_spam(obj, "nv_wo32 0x%08x 0x%08x\n", addr, data);
|
||||
nv_spam(obj, "nv_wo32 0x%08llx 0x%08x\n", addr, data);
|
||||
nv_ofuncs(obj)->wr32(obj, addr, data);
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,8 @@ struct nouveau_object;
|
||||
#define NV_PRINTK_TRACE KERN_DEBUG
|
||||
#define NV_PRINTK_SPAM KERN_DEBUG
|
||||
|
||||
void nv_printk_(struct nouveau_object *, const char *, int, const char *, ...);
|
||||
void __printf(4, 5)
|
||||
nv_printk_(struct nouveau_object *, const char *, int, const char *, ...);
|
||||
|
||||
#define nv_printk(o,l,f,a...) do { \
|
||||
if (NV_DBG_##l <= CONFIG_NOUVEAU_DEBUG) \
|
||||
|
@ -4,18 +4,11 @@
|
||||
#include <core/object.h>
|
||||
#include <core/engine.h>
|
||||
#include <core/device.h>
|
||||
#include <core/event.h>
|
||||
|
||||
struct nouveau_disp {
|
||||
struct nouveau_engine base;
|
||||
|
||||
struct {
|
||||
struct list_head list;
|
||||
spinlock_t lock;
|
||||
void (*notify)(void *, int);
|
||||
void (*get)(void *, int);
|
||||
void (*put)(void *, int);
|
||||
void *data;
|
||||
} vblank;
|
||||
struct nouveau_event *vblank;
|
||||
};
|
||||
|
||||
static inline struct nouveau_disp *
|
||||
@ -24,16 +17,22 @@ nouveau_disp(void *obj)
|
||||
return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_DISP];
|
||||
}
|
||||
|
||||
#define nouveau_disp_create(p,e,c,i,x,d) \
|
||||
nouveau_engine_create((p), (e), (c), true, (i), (x), (d))
|
||||
#define nouveau_disp_destroy(d) \
|
||||
nouveau_engine_destroy(&(d)->base)
|
||||
#define nouveau_disp_create(p,e,c,h,i,x,d) \
|
||||
nouveau_disp_create_((p), (e), (c), (h), (i), (x), \
|
||||
sizeof(**d), (void **)d)
|
||||
#define nouveau_disp_destroy(d) ({ \
|
||||
struct nouveau_disp *disp = (d); \
|
||||
_nouveau_disp_dtor(nv_object(disp)); \
|
||||
})
|
||||
#define nouveau_disp_init(d) \
|
||||
nouveau_engine_init(&(d)->base)
|
||||
#define nouveau_disp_fini(d,s) \
|
||||
nouveau_engine_fini(&(d)->base, (s))
|
||||
|
||||
#define _nouveau_disp_dtor _nouveau_engine_dtor
|
||||
int nouveau_disp_create_(struct nouveau_object *, struct nouveau_object *,
|
||||
struct nouveau_oclass *, int heads,
|
||||
const char *, const char *, int, void **);
|
||||
void _nouveau_disp_dtor(struct nouveau_object *);
|
||||
#define _nouveau_disp_init _nouveau_engine_init
|
||||
#define _nouveau_disp_fini _nouveau_engine_fini
|
||||
|
||||
|
@ -65,6 +65,8 @@ struct nouveau_fifo_base {
|
||||
struct nouveau_fifo {
|
||||
struct nouveau_engine base;
|
||||
|
||||
struct nouveau_event *uevent;
|
||||
|
||||
struct nouveau_object **channel;
|
||||
spinlock_t lock;
|
||||
u16 min;
|
||||
@ -92,6 +94,8 @@ int nouveau_fifo_create_(struct nouveau_object *, struct nouveau_object *,
|
||||
struct nouveau_oclass *, int min, int max,
|
||||
int size, void **);
|
||||
void nouveau_fifo_destroy(struct nouveau_fifo *);
|
||||
const char *
|
||||
nouveau_client_name_for_fifo_chid(struct nouveau_fifo *fifo, u32 chid);
|
||||
|
||||
#define _nouveau_fifo_init _nouveau_engine_init
|
||||
#define _nouveau_fifo_fini _nouveau_engine_fini
|
||||
|
@ -3,17 +3,17 @@
|
||||
|
||||
#include <core/engine.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/event.h>
|
||||
|
||||
struct nouveau_software_chan {
|
||||
struct nouveau_engctx base;
|
||||
|
||||
struct {
|
||||
struct list_head head;
|
||||
struct nouveau_eventh event;
|
||||
u32 channel;
|
||||
u32 ctxdma;
|
||||
u64 offset;
|
||||
u32 value;
|
||||
u32 crtc;
|
||||
} vblank;
|
||||
|
||||
int (*flip)(void *);
|
||||
|
@ -16,6 +16,8 @@ enum dcb_output_type {
|
||||
|
||||
struct dcb_output {
|
||||
int index; /* may not be raw dcb index if merging has happened */
|
||||
u16 hasht;
|
||||
u16 hashm;
|
||||
enum dcb_output_type type;
|
||||
uint8_t i2c_index;
|
||||
uint8_t heads;
|
||||
@ -25,6 +27,7 @@ struct dcb_output {
|
||||
uint8_t or;
|
||||
uint8_t link;
|
||||
bool duallink_possible;
|
||||
uint8_t extdev;
|
||||
union {
|
||||
struct sor_conf {
|
||||
int link;
|
||||
|
@ -1,17 +1,22 @@
|
||||
#ifndef __NVBIOS_GPIO_H__
|
||||
#define __NVBIOS_GPIO_H__
|
||||
|
||||
struct nouveau_bios;
|
||||
|
||||
enum dcb_gpio_func_name {
|
||||
DCB_GPIO_PANEL_POWER = 0x01,
|
||||
DCB_GPIO_TVDAC0 = 0x0c,
|
||||
DCB_GPIO_TVDAC1 = 0x2d,
|
||||
DCB_GPIO_PWM_FAN = 0x09,
|
||||
DCB_GPIO_FAN = 0x09,
|
||||
DCB_GPIO_FAN_SENSE = 0x3d,
|
||||
DCB_GPIO_UNUSED = 0xff
|
||||
};
|
||||
|
||||
#define DCB_GPIO_LOG_DIR 0x02
|
||||
#define DCB_GPIO_LOG_DIR_OUT 0x00
|
||||
#define DCB_GPIO_LOG_DIR_IN 0x02
|
||||
#define DCB_GPIO_LOG_VAL 0x01
|
||||
#define DCB_GPIO_LOG_VAL_LO 0x00
|
||||
#define DCB_GPIO_LOG_VAL_HI 0x01
|
||||
|
||||
struct dcb_gpio_func {
|
||||
u8 func;
|
||||
u8 line;
|
||||
|
@ -15,7 +15,7 @@ struct dcb_i2c_entry {
|
||||
enum dcb_i2c_type type;
|
||||
u8 drive;
|
||||
u8 sense;
|
||||
u32 data;
|
||||
u8 share;
|
||||
};
|
||||
|
||||
u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
|
||||
|
@ -23,11 +23,27 @@ struct nvbios_therm_sensor {
|
||||
struct nvbios_therm_threshold thrs_shutdown;
|
||||
};
|
||||
|
||||
/* no vbios have more than 6 */
|
||||
#define NOUVEAU_TEMP_FAN_TRIP_MAX 10
|
||||
struct nouveau_therm_trip_point {
|
||||
int fan_duty;
|
||||
int temp;
|
||||
int hysteresis;
|
||||
};
|
||||
|
||||
struct nvbios_therm_fan {
|
||||
u16 pwm_freq;
|
||||
|
||||
u8 min_duty;
|
||||
u8 max_duty;
|
||||
|
||||
u16 bump_period;
|
||||
u16 slow_down_period;
|
||||
|
||||
struct nouveau_therm_trip_point trip[NOUVEAU_TEMP_FAN_TRIP_MAX];
|
||||
u8 nr_fan_trip;
|
||||
u8 linear_min_temp;
|
||||
u8 linear_max_temp;
|
||||
};
|
||||
|
||||
enum nvbios_therm_domain {
|
||||
|
19
drivers/gpu/drm/nouveau/core/include/subdev/bios/xpio.h
Normal file
19
drivers/gpu/drm/nouveau/core/include/subdev/bios/xpio.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef __NVBIOS_XPIO_H__
|
||||
#define __NVBIOS_XPIO_H__
|
||||
|
||||
#define NVBIOS_XPIO_FLAG_AUX 0x10
|
||||
#define NVBIOS_XPIO_FLAG_AUX0 0x00
|
||||
#define NVBIOS_XPIO_FLAG_AUX1 0x10
|
||||
|
||||
struct nvbios_xpio {
|
||||
u8 type;
|
||||
u8 addr;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
u16 dcb_xpio_table(struct nouveau_bios *, u8 idx,
|
||||
u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
|
||||
u16 dcb_xpio_parse(struct nouveau_bios *, u8 idx,
|
||||
u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_xpio *);
|
||||
|
||||
#endif
|
41
drivers/gpu/drm/nouveau/core/include/subdev/bus.h
Normal file
41
drivers/gpu/drm/nouveau/core/include/subdev/bus.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef __NOUVEAU_BUS_H__
|
||||
#define __NOUVEAU_BUS_H__
|
||||
|
||||
#include <core/subdev.h>
|
||||
#include <core/device.h>
|
||||
|
||||
struct nouveau_bus_intr {
|
||||
u32 stat;
|
||||
u32 unit;
|
||||
};
|
||||
|
||||
struct nouveau_bus {
|
||||
struct nouveau_subdev base;
|
||||
};
|
||||
|
||||
static inline struct nouveau_bus *
|
||||
nouveau_bus(void *obj)
|
||||
{
|
||||
return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_BUS];
|
||||
}
|
||||
|
||||
#define nouveau_bus_create(p, e, o, d) \
|
||||
nouveau_subdev_create_((p), (e), (o), 0, "PBUS", "master", \
|
||||
sizeof(**d), (void **)d)
|
||||
#define nouveau_bus_destroy(p) \
|
||||
nouveau_subdev_destroy(&(p)->base)
|
||||
#define nouveau_bus_init(p) \
|
||||
nouveau_subdev_init(&(p)->base)
|
||||
#define nouveau_bus_fini(p, s) \
|
||||
nouveau_subdev_fini(&(p)->base, (s))
|
||||
|
||||
#define _nouveau_bus_dtor _nouveau_subdev_dtor
|
||||
#define _nouveau_bus_init _nouveau_subdev_init
|
||||
#define _nouveau_bus_fini _nouveau_subdev_fini
|
||||
|
||||
extern struct nouveau_oclass nv04_bus_oclass;
|
||||
extern struct nouveau_oclass nv31_bus_oclass;
|
||||
extern struct nouveau_oclass nv50_bus_oclass;
|
||||
extern struct nouveau_oclass nvc0_bus_oclass;
|
||||
|
||||
#endif
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <core/subdev.h>
|
||||
#include <core/device.h>
|
||||
#include <core/event.h>
|
||||
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bios/gpio.h>
|
||||
@ -10,28 +11,18 @@
|
||||
struct nouveau_gpio {
|
||||
struct nouveau_subdev base;
|
||||
|
||||
struct nouveau_event *events;
|
||||
|
||||
/* hardware interfaces */
|
||||
void (*reset)(struct nouveau_gpio *, u8 func);
|
||||
int (*drive)(struct nouveau_gpio *, int line, int dir, int out);
|
||||
int (*sense)(struct nouveau_gpio *, int line);
|
||||
void (*irq_enable)(struct nouveau_gpio *, int line, bool);
|
||||
|
||||
/* software interfaces */
|
||||
int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
|
||||
struct dcb_gpio_func *);
|
||||
int (*set)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int state);
|
||||
int (*get)(struct nouveau_gpio *, int idx, u8 tag, u8 line);
|
||||
int (*irq)(struct nouveau_gpio *, int idx, u8 tag, u8 line, bool on);
|
||||
|
||||
/* interrupt handling */
|
||||
struct list_head isr;
|
||||
spinlock_t lock;
|
||||
|
||||
void (*isr_run)(struct nouveau_gpio *, int idx, u32 mask);
|
||||
int (*isr_add)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
|
||||
void (*)(void *, int state), void *data);
|
||||
void (*isr_del)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
|
||||
void (*)(void *, int state), void *data);
|
||||
};
|
||||
|
||||
static inline struct nouveau_gpio *
|
||||
@ -40,25 +31,23 @@ nouveau_gpio(void *obj)
|
||||
return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_GPIO];
|
||||
}
|
||||
|
||||
#define nouveau_gpio_create(p,e,o,d) \
|
||||
nouveau_gpio_create_((p), (e), (o), sizeof(**d), (void **)d)
|
||||
#define nouveau_gpio_destroy(p) \
|
||||
nouveau_subdev_destroy(&(p)->base)
|
||||
#define nouveau_gpio_create(p,e,o,l,d) \
|
||||
nouveau_gpio_create_((p), (e), (o), (l), sizeof(**d), (void **)d)
|
||||
#define nouveau_gpio_destroy(p) ({ \
|
||||
struct nouveau_gpio *gpio = (p); \
|
||||
_nouveau_gpio_dtor(nv_object(gpio)); \
|
||||
})
|
||||
#define nouveau_gpio_fini(p,s) \
|
||||
nouveau_subdev_fini(&(p)->base, (s))
|
||||
|
||||
int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *,
|
||||
struct nouveau_oclass *, int, void **);
|
||||
int nouveau_gpio_init(struct nouveau_gpio *);
|
||||
int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *,
|
||||
struct nouveau_oclass *, int, int, void **);
|
||||
void _nouveau_gpio_dtor(struct nouveau_object *);
|
||||
int nouveau_gpio_init(struct nouveau_gpio *);
|
||||
|
||||
extern struct nouveau_oclass nv10_gpio_oclass;
|
||||
extern struct nouveau_oclass nv50_gpio_oclass;
|
||||
extern struct nouveau_oclass nvd0_gpio_oclass;
|
||||
|
||||
void nv50_gpio_dtor(struct nouveau_object *);
|
||||
int nv50_gpio_init(struct nouveau_object *);
|
||||
int nv50_gpio_fini(struct nouveau_object *, bool);
|
||||
void nv50_gpio_intr(struct nouveau_subdev *);
|
||||
void nv50_gpio_irq_enable(struct nouveau_gpio *, int line, bool);
|
||||
extern struct nouveau_oclass nve0_gpio_oclass;
|
||||
|
||||
#endif
|
||||
|
@ -10,23 +10,59 @@
|
||||
#define NV_I2C_PORT(n) (0x00 + (n))
|
||||
#define NV_I2C_DEFAULT(n) (0x80 + (n))
|
||||
|
||||
#define NV_I2C_TYPE_DCBI2C(n) (0x0000 | (n))
|
||||
#define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8)
|
||||
#define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8)
|
||||
|
||||
struct nouveau_i2c_port {
|
||||
struct nouveau_object base;
|
||||
struct i2c_adapter adapter;
|
||||
struct nouveau_i2c *i2c;
|
||||
struct i2c_algo_bit_data bit;
|
||||
|
||||
struct list_head head;
|
||||
u8 index;
|
||||
u8 type;
|
||||
u32 dcb;
|
||||
u32 drive;
|
||||
u32 sense;
|
||||
u32 state;
|
||||
|
||||
const struct nouveau_i2c_func *func;
|
||||
};
|
||||
|
||||
struct nouveau_i2c_func {
|
||||
void (*acquire)(struct nouveau_i2c_port *);
|
||||
void (*release)(struct nouveau_i2c_port *);
|
||||
|
||||
void (*drive_scl)(struct nouveau_i2c_port *, int);
|
||||
void (*drive_sda)(struct nouveau_i2c_port *, int);
|
||||
int (*sense_scl)(struct nouveau_i2c_port *);
|
||||
int (*sense_sda)(struct nouveau_i2c_port *);
|
||||
|
||||
int (*aux)(struct nouveau_i2c_port *, u8, u32, u8 *, u8);
|
||||
int (*pattern)(struct nouveau_i2c_port *, int pattern);
|
||||
int (*lnk_ctl)(struct nouveau_i2c_port *, int nr, int bw, bool enh);
|
||||
int (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe);
|
||||
};
|
||||
|
||||
#define nouveau_i2c_port_create(p,e,o,i,a,d) \
|
||||
nouveau_i2c_port_create_((p), (e), (o), (i), (a), \
|
||||
sizeof(**d), (void **)d)
|
||||
#define nouveau_i2c_port_destroy(p) ({ \
|
||||
struct nouveau_i2c_port *port = (p); \
|
||||
_nouveau_i2c_port_dtor(nv_object(i2c)); \
|
||||
})
|
||||
#define nouveau_i2c_port_init(p) \
|
||||
nouveau_object_init(&(p)->base)
|
||||
#define nouveau_i2c_port_fini(p,s) \
|
||||
nouveau_object_fini(&(p)->base, (s))
|
||||
|
||||
int nouveau_i2c_port_create_(struct nouveau_object *, struct nouveau_object *,
|
||||
struct nouveau_oclass *, u8,
|
||||
const struct i2c_algorithm *, int, void **);
|
||||
void _nouveau_i2c_port_dtor(struct nouveau_object *);
|
||||
#define _nouveau_i2c_port_init nouveau_object_init
|
||||
#define _nouveau_i2c_port_fini nouveau_object_fini
|
||||
|
||||
struct nouveau_i2c {
|
||||
struct nouveau_subdev base;
|
||||
|
||||
struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index);
|
||||
struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type);
|
||||
int (*identify)(struct nouveau_i2c *, int index,
|
||||
const char *what, struct i2c_board_info *,
|
||||
bool (*match)(struct nouveau_i2c_port *,
|
||||
@ -40,21 +76,76 @@ nouveau_i2c(void *obj)
|
||||
return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_I2C];
|
||||
}
|
||||
|
||||
extern struct nouveau_oclass nouveau_i2c_oclass;
|
||||
#define nouveau_i2c_create(p,e,o,s,d) \
|
||||
nouveau_i2c_create_((p), (e), (o), (s), sizeof(**d), (void **)d)
|
||||
#define nouveau_i2c_destroy(p) ({ \
|
||||
struct nouveau_i2c *i2c = (p); \
|
||||
_nouveau_i2c_dtor(nv_object(i2c)); \
|
||||
})
|
||||
#define nouveau_i2c_init(p) ({ \
|
||||
struct nouveau_i2c *i2c = (p); \
|
||||
_nouveau_i2c_init(nv_object(i2c)); \
|
||||
})
|
||||
#define nouveau_i2c_fini(p,s) ({ \
|
||||
struct nouveau_i2c *i2c = (p); \
|
||||
_nouveau_i2c_fini(nv_object(i2c), (s)); \
|
||||
})
|
||||
|
||||
void nouveau_i2c_drive_scl(void *, int);
|
||||
void nouveau_i2c_drive_sda(void *, int);
|
||||
int nouveau_i2c_sense_scl(void *);
|
||||
int nouveau_i2c_sense_sda(void *);
|
||||
int nouveau_i2c_create_(struct nouveau_object *, struct nouveau_object *,
|
||||
struct nouveau_oclass *, struct nouveau_oclass *,
|
||||
int, void **);
|
||||
void _nouveau_i2c_dtor(struct nouveau_object *);
|
||||
int _nouveau_i2c_init(struct nouveau_object *);
|
||||
int _nouveau_i2c_fini(struct nouveau_object *, bool);
|
||||
|
||||
int nv_rdi2cr(struct nouveau_i2c_port *, u8 addr, u8 reg);
|
||||
int nv_wri2cr(struct nouveau_i2c_port *, u8 addr, u8 reg, u8 val);
|
||||
bool nv_probe_i2c(struct nouveau_i2c_port *, u8 addr);
|
||||
|
||||
int nv_rdaux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size);
|
||||
int nv_wraux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size);
|
||||
extern struct nouveau_oclass nv04_i2c_oclass;
|
||||
extern struct nouveau_oclass nv4e_i2c_oclass;
|
||||
extern struct nouveau_oclass nv50_i2c_oclass;
|
||||
extern struct nouveau_oclass nv94_i2c_oclass;
|
||||
extern struct nouveau_oclass nvd0_i2c_oclass;
|
||||
extern struct nouveau_oclass nouveau_anx9805_sclass[];
|
||||
|
||||
extern const struct i2c_algorithm nouveau_i2c_bit_algo;
|
||||
extern const struct i2c_algorithm nouveau_i2c_aux_algo;
|
||||
|
||||
static inline int
|
||||
nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg)
|
||||
{
|
||||
u8 val;
|
||||
struct i2c_msg msgs[] = {
|
||||
{ .addr = addr, .flags = 0, .len = 1, .buf = ® },
|
||||
{ .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = &val },
|
||||
};
|
||||
|
||||
int ret = i2c_transfer(&port->adapter, msgs, 2);
|
||||
if (ret != 2)
|
||||
return -EIO;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline int
|
||||
nv_wri2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg, u8 val)
|
||||
{
|
||||
u8 buf[2] = { reg, val };
|
||||
struct i2c_msg msgs[] = {
|
||||
{ .addr = addr, .flags = 0, .len = 2, .buf = buf },
|
||||
};
|
||||
|
||||
int ret = i2c_transfer(&port->adapter, msgs, 1);
|
||||
if (ret != 1)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
nv_probe_i2c(struct nouveau_i2c_port *port, u8 addr)
|
||||
{
|
||||
return nv_rdi2cr(port, addr, 0) >= 0;
|
||||
}
|
||||
|
||||
int nv_rdaux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size);
|
||||
int nv_wraux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size);
|
||||
|
||||
#endif
|
||||
|
@ -4,10 +4,10 @@
|
||||
#include <core/device.h>
|
||||
#include <core/subdev.h>
|
||||
|
||||
enum nouveau_therm_fan_mode {
|
||||
FAN_CONTROL_NONE = 0,
|
||||
FAN_CONTROL_MANUAL = 1,
|
||||
FAN_CONTROL_NR,
|
||||
enum nouveau_therm_mode {
|
||||
NOUVEAU_THERM_CTRL_NONE = 0,
|
||||
NOUVEAU_THERM_CTRL_MANUAL = 1,
|
||||
NOUVEAU_THERM_CTRL_AUTO = 2,
|
||||
};
|
||||
|
||||
enum nouveau_therm_attr_type {
|
||||
@ -28,6 +28,11 @@ enum nouveau_therm_attr_type {
|
||||
struct nouveau_therm {
|
||||
struct nouveau_subdev base;
|
||||
|
||||
int (*pwm_ctrl)(struct nouveau_therm *, int line, bool);
|
||||
int (*pwm_get)(struct nouveau_therm *, int line, u32 *, u32 *);
|
||||
int (*pwm_set)(struct nouveau_therm *, int line, u32, u32);
|
||||
int (*pwm_clock)(struct nouveau_therm *);
|
||||
|
||||
int (*fan_get)(struct nouveau_therm *);
|
||||
int (*fan_set)(struct nouveau_therm *, int);
|
||||
int (*fan_sense)(struct nouveau_therm *);
|
||||
@ -46,13 +51,29 @@ nouveau_therm(void *obj)
|
||||
}
|
||||
|
||||
#define nouveau_therm_create(p,e,o,d) \
|
||||
nouveau_subdev_create((p), (e), (o), 0, "THERM", "therm", d)
|
||||
#define nouveau_therm_destroy(p) \
|
||||
nouveau_subdev_destroy(&(p)->base)
|
||||
nouveau_therm_create_((p), (e), (o), sizeof(**d), (void **)d)
|
||||
#define nouveau_therm_destroy(p) ({ \
|
||||
struct nouveau_therm *therm = (p); \
|
||||
_nouveau_therm_dtor(nv_object(therm)); \
|
||||
})
|
||||
#define nouveau_therm_init(p) ({ \
|
||||
struct nouveau_therm *therm = (p); \
|
||||
_nouveau_therm_init(nv_object(therm)); \
|
||||
})
|
||||
#define nouveau_therm_fini(p,s) ({ \
|
||||
struct nouveau_therm *therm = (p); \
|
||||
_nouveau_therm_init(nv_object(therm), (s)); \
|
||||
})
|
||||
|
||||
#define _nouveau_therm_dtor _nouveau_subdev_dtor
|
||||
int nouveau_therm_create_(struct nouveau_object *, struct nouveau_object *,
|
||||
struct nouveau_oclass *, int, void **);
|
||||
void _nouveau_therm_dtor(struct nouveau_object *);
|
||||
int _nouveau_therm_init(struct nouveau_object *);
|
||||
int _nouveau_therm_fini(struct nouveau_object *, bool);
|
||||
|
||||
extern struct nouveau_oclass nv40_therm_oclass;
|
||||
extern struct nouveau_oclass nv50_therm_oclass;
|
||||
extern struct nouveau_oclass nva3_therm_oclass;
|
||||
extern struct nouveau_oclass nvd0_therm_oclass;
|
||||
|
||||
#endif
|
||||
|
@ -10,6 +10,14 @@ struct nouveau_alarm {
|
||||
void (*func)(struct nouveau_alarm *);
|
||||
};
|
||||
|
||||
static inline void
|
||||
nouveau_alarm_init(struct nouveau_alarm *alarm,
|
||||
void (*func)(struct nouveau_alarm *))
|
||||
{
|
||||
INIT_LIST_HEAD(&alarm->head);
|
||||
alarm->func = func;
|
||||
}
|
||||
|
||||
bool nouveau_timer_wait_eq(void *, u64 nsec, u32 addr, u32 mask, u32 data);
|
||||
bool nouveau_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data);
|
||||
bool nouveau_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/reboot.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
|
@ -172,7 +172,7 @@ out:
|
||||
nv_wr32(bios, pcireg, access);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ACPI)
|
||||
#if defined(CONFIG_ACPI) && defined(CONFIG_X86)
|
||||
int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
|
||||
bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
|
||||
#else
|
||||
|
@ -107,6 +107,18 @@ dcb_outp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len)
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
static inline u16
|
||||
dcb_outp_hasht(struct dcb_output *outp)
|
||||
{
|
||||
return (outp->extdev << 8) | (outp->location << 4) | outp->type;
|
||||
}
|
||||
|
||||
static inline u16
|
||||
dcb_outp_hashm(struct dcb_output *outp)
|
||||
{
|
||||
return (outp->heads << 8) | (outp->link << 6) | outp->or;
|
||||
}
|
||||
|
||||
u16
|
||||
dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len,
|
||||
struct dcb_output *outp)
|
||||
@ -135,34 +147,28 @@ dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len,
|
||||
case DCB_OUTPUT_DP:
|
||||
outp->link = (conf & 0x00000030) >> 4;
|
||||
outp->sorconf.link = outp->link; /*XXX*/
|
||||
outp->extdev = 0x00;
|
||||
if (outp->location != 0)
|
||||
outp->extdev = (conf & 0x0000ff00) >> 8;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
outp->hasht = dcb_outp_hasht(outp);
|
||||
outp->hashm = dcb_outp_hashm(outp);
|
||||
}
|
||||
return dcb;
|
||||
}
|
||||
|
||||
static inline u16
|
||||
dcb_outp_hasht(struct dcb_output *outp)
|
||||
{
|
||||
return outp->type;
|
||||
}
|
||||
|
||||
static inline u16
|
||||
dcb_outp_hashm(struct dcb_output *outp)
|
||||
{
|
||||
return (outp->heads << 8) | (outp->link << 6) | outp->or;
|
||||
}
|
||||
|
||||
u16
|
||||
dcb_outp_match(struct nouveau_bios *bios, u16 type, u16 mask,
|
||||
u8 *ver, u8 *len, struct dcb_output *outp)
|
||||
{
|
||||
u16 dcb, idx = 0;
|
||||
while ((dcb = dcb_outp_parse(bios, idx++, ver, len, outp))) {
|
||||
if (dcb_outp_hasht(outp) == type) {
|
||||
if ((dcb_outp_hasht(outp) & 0x00ff) == (type & 0x00ff)) {
|
||||
if ((dcb_outp_hashm(outp) & mask) == mask)
|
||||
break;
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ extdev_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt)
|
||||
return extdev + *hdr;
|
||||
}
|
||||
|
||||
u16
|
||||
static u16
|
||||
nvbios_extdev_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
|
||||
{
|
||||
u8 hdr, cnt;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bios/dcb.h>
|
||||
#include <subdev/bios/gpio.h>
|
||||
#include <subdev/bios/xpio.h>
|
||||
|
||||
u16
|
||||
dcb_gpio_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
|
||||
@ -60,8 +61,14 @@ dcb_gpio_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
|
||||
u16
|
||||
dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len)
|
||||
{
|
||||
u8 hdr, cnt;
|
||||
u16 gpio = !idx ? dcb_gpio_table(bios, ver, &hdr, &cnt, len) : 0x0000;
|
||||
u8 hdr, cnt, xver; /* use gpio version for xpio entry parsing */
|
||||
u16 gpio;
|
||||
|
||||
if (!idx--)
|
||||
gpio = dcb_gpio_table(bios, ver, &hdr, &cnt, len);
|
||||
else
|
||||
gpio = dcb_xpio_table(bios, idx, &xver, &hdr, &cnt, len);
|
||||
|
||||
if (gpio && ent < cnt)
|
||||
return gpio + hdr + (ent * *len);
|
||||
return 0x0000;
|
||||
|
@ -70,12 +70,12 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info)
|
||||
u8 ver, len;
|
||||
u16 ent = dcb_i2c_entry(bios, idx, &ver, &len);
|
||||
if (ent) {
|
||||
info->data = nv_ro32(bios, ent + 0);
|
||||
info->type = nv_ro08(bios, ent + 3);
|
||||
info->type = nv_ro08(bios, ent + 3);
|
||||
info->share = DCB_I2C_UNUSED;
|
||||
if (ver < 0x30) {
|
||||
info->type &= 0x07;
|
||||
if (info->type == 0x07)
|
||||
info->type = 0xff;
|
||||
info->type = DCB_I2C_UNUSED;
|
||||
}
|
||||
|
||||
switch (info->type) {
|
||||
@ -88,7 +88,11 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info)
|
||||
return 0;
|
||||
case DCB_I2C_NVIO_BIT:
|
||||
case DCB_I2C_NVIO_AUX:
|
||||
info->drive = nv_ro08(bios, ent + 0);
|
||||
info->drive = nv_ro08(bios, ent + 0) & 0x0f;
|
||||
if (nv_ro08(bios, ent + 1) & 0x01) {
|
||||
info->share = nv_ro08(bios, ent + 1) >> 1;
|
||||
info->share &= 0x0f;
|
||||
}
|
||||
return 0;
|
||||
case DCB_I2C_UNUSED:
|
||||
return 0;
|
||||
@ -121,7 +125,8 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info)
|
||||
if (!info->sense) info->sense = 0x36;
|
||||
}
|
||||
|
||||
info->type = DCB_I2C_NV04_BIT;
|
||||
info->type = DCB_I2C_NV04_BIT;
|
||||
info->share = DCB_I2C_UNUSED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -231,6 +231,11 @@ init_i2c(struct nvbios_init *init, int index)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (index == -2 && init->outp->location) {
|
||||
index = NV_I2C_TYPE_EXTAUX(init->outp->extdev);
|
||||
return i2c->find_type(i2c, index);
|
||||
}
|
||||
|
||||
index = init->outp->i2c_index;
|
||||
}
|
||||
|
||||
@ -258,7 +263,7 @@ init_wri2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg, u8 val)
|
||||
static int
|
||||
init_rdauxr(struct nvbios_init *init, u32 addr)
|
||||
{
|
||||
struct nouveau_i2c_port *port = init_i2c(init, -1);
|
||||
struct nouveau_i2c_port *port = init_i2c(init, -2);
|
||||
u8 data;
|
||||
|
||||
if (port && init_exec(init)) {
|
||||
@ -274,7 +279,7 @@ init_rdauxr(struct nvbios_init *init, u32 addr)
|
||||
static int
|
||||
init_wrauxr(struct nvbios_init *init, u32 addr, u8 data)
|
||||
{
|
||||
struct nouveau_i2c_port *port = init_i2c(init, -1);
|
||||
struct nouveau_i2c_port *port = init_i2c(init, -2);
|
||||
if (port && init_exec(init))
|
||||
return nv_wraux(port, addr, &data, 1);
|
||||
return -ENODEV;
|
||||
@ -1816,7 +1821,7 @@ init_ram_restrict_zm_reg_group(struct nvbios_init *init)
|
||||
u8 i, j;
|
||||
|
||||
trace("RAM_RESTRICT_ZM_REG_GROUP\t"
|
||||
"R[%08x] 0x%02x 0x%02x\n", addr, incr, num);
|
||||
"R[0x%08x] 0x%02x 0x%02x\n", addr, incr, num);
|
||||
init->offset += 7;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
@ -1849,7 +1854,7 @@ init_copy_zm_reg(struct nvbios_init *init)
|
||||
u32 sreg = nv_ro32(bios, init->offset + 1);
|
||||
u32 dreg = nv_ro32(bios, init->offset + 5);
|
||||
|
||||
trace("COPY_ZM_REG\tR[0x%06x] = R[0x%06x]\n", sreg, dreg);
|
||||
trace("COPY_ZM_REG\tR[0x%06x] = R[0x%06x]\n", dreg, sreg);
|
||||
init->offset += 9;
|
||||
|
||||
init_wr32(init, dreg, init_rd32(init, sreg));
|
||||
@ -1866,7 +1871,7 @@ init_zm_reg_group(struct nvbios_init *init)
|
||||
u32 addr = nv_ro32(bios, init->offset + 1);
|
||||
u8 count = nv_ro08(bios, init->offset + 5);
|
||||
|
||||
trace("ZM_REG_GROUP\tR[0x%06x] =\n");
|
||||
trace("ZM_REG_GROUP\tR[0x%06x] =\n", addr);
|
||||
init->offset += 6;
|
||||
|
||||
while (count--) {
|
||||
|
@ -55,7 +55,7 @@ therm_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt)
|
||||
return therm + nv_ro08(bios, therm + 1);
|
||||
}
|
||||
|
||||
u16
|
||||
static u16
|
||||
nvbios_therm_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
|
||||
{
|
||||
u8 hdr, cnt;
|
||||
@ -155,10 +155,15 @@ int
|
||||
nvbios_therm_fan_parse(struct nouveau_bios *bios,
|
||||
struct nvbios_therm_fan *fan)
|
||||
{
|
||||
struct nouveau_therm_trip_point *cur_trip = NULL;
|
||||
u8 ver, len, i;
|
||||
u16 entry;
|
||||
|
||||
uint8_t duty_lut[] = { 0, 0, 25, 0, 40, 0, 50, 0,
|
||||
75, 0, 85, 0, 100, 0, 100, 0 };
|
||||
|
||||
i = 0;
|
||||
fan->nr_fan_trip = 0;
|
||||
while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) {
|
||||
s16 value = nv_ro16(bios, entry + 1);
|
||||
|
||||
@ -167,9 +172,30 @@ nvbios_therm_fan_parse(struct nouveau_bios *bios,
|
||||
fan->min_duty = value & 0xff;
|
||||
fan->max_duty = (value & 0xff00) >> 8;
|
||||
break;
|
||||
case 0x24:
|
||||
fan->nr_fan_trip++;
|
||||
cur_trip = &fan->trip[fan->nr_fan_trip - 1];
|
||||
cur_trip->hysteresis = value & 0xf;
|
||||
cur_trip->temp = (value & 0xff0) >> 4;
|
||||
cur_trip->fan_duty = duty_lut[(value & 0xf000) >> 12];
|
||||
break;
|
||||
case 0x25:
|
||||
cur_trip = &fan->trip[fan->nr_fan_trip - 1];
|
||||
cur_trip->fan_duty = value;
|
||||
break;
|
||||
case 0x26:
|
||||
fan->pwm_freq = value;
|
||||
break;
|
||||
case 0x3b:
|
||||
fan->bump_period = value;
|
||||
break;
|
||||
case 0x3c:
|
||||
fan->slow_down_period = value;
|
||||
break;
|
||||
case 0x46:
|
||||
fan->linear_min_temp = nv_ro08(bios, entry + 1);
|
||||
fan->linear_max_temp = nv_ro08(bios, entry + 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
76
drivers/gpu/drm/nouveau/core/subdev/bios/xpio.c
Normal file
76
drivers/gpu/drm/nouveau/core/subdev/bios/xpio.c
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 <subdev/bios.h>
|
||||
#include <subdev/bios/gpio.h>
|
||||
#include <subdev/bios/xpio.h>
|
||||
|
||||
static u16
|
||||
dcb_xpiod_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
|
||||
{
|
||||
u16 data = dcb_gpio_table(bios, ver, hdr, cnt, len);
|
||||
if (data && *ver >= 0x40 && *hdr >= 0x06) {
|
||||
u16 xpio = nv_ro16(bios, data + 0x04);
|
||||
if (xpio) {
|
||||
*ver = nv_ro08(bios, data + 0x00);
|
||||
*hdr = nv_ro08(bios, data + 0x01);
|
||||
*cnt = nv_ro08(bios, data + 0x02);
|
||||
*len = nv_ro08(bios, data + 0x03);
|
||||
return xpio;
|
||||
}
|
||||
}
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
u16
|
||||
dcb_xpio_table(struct nouveau_bios *bios, u8 idx,
|
||||
u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
|
||||
{
|
||||
u16 data = dcb_xpiod_table(bios, ver, hdr, cnt, len);
|
||||
if (data && idx < *cnt) {
|
||||
u16 xpio = nv_ro16(bios, data + *hdr + (idx * *len));
|
||||
if (xpio) {
|
||||
*ver = nv_ro08(bios, data + 0x00);
|
||||
*hdr = nv_ro08(bios, data + 0x01);
|
||||
*cnt = nv_ro08(bios, data + 0x02);
|
||||
*len = nv_ro08(bios, data + 0x03);
|
||||
return xpio;
|
||||
}
|
||||
}
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
u16
|
||||
dcb_xpio_parse(struct nouveau_bios *bios, u8 idx,
|
||||
u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
|
||||
struct nvbios_xpio *info)
|
||||
{
|
||||
u16 data = dcb_xpio_table(bios, idx, ver, hdr, cnt, len);
|
||||
if (data && *len >= 6) {
|
||||
info->type = nv_ro08(bios, data + 0x04);
|
||||
info->addr = nv_ro08(bios, data + 0x05);
|
||||
info->flags = nv_ro08(bios, data + 0x06);
|
||||
}
|
||||
return 0x0000;
|
||||
}
|
95
drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c
Normal file
95
drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2012 Nouveau Community
|
||||
*
|
||||
* 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: Martin Peres <martin.peres@labri.fr>
|
||||
* Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <subdev/bus.h>
|
||||
|
||||
struct nv04_bus_priv {
|
||||
struct nouveau_bus base;
|
||||
};
|
||||
|
||||
static void
|
||||
nv04_bus_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nouveau_bus *pbus = nouveau_bus(subdev);
|
||||
u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
|
||||
|
||||
if (stat & 0x00000001) {
|
||||
nv_error(pbus, "BUS ERROR\n");
|
||||
stat &= ~0x00000001;
|
||||
nv_wr32(pbus, 0x001100, 0x00000001);
|
||||
}
|
||||
|
||||
if (stat & 0x00000110) {
|
||||
subdev = nouveau_subdev(subdev, NVDEV_SUBDEV_GPIO);
|
||||
if (subdev && subdev->intr)
|
||||
subdev->intr(subdev);
|
||||
stat &= ~0x00000110;
|
||||
nv_wr32(pbus, 0x001100, 0x00000110);
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
nv_error(pbus, "unknown intr 0x%08x\n", stat);
|
||||
nv_mask(pbus, 0x001140, stat, 0x00000000);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nv04_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv04_bus_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_bus_create(parent, engine, oclass, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->intr = nv04_bus_intr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv04_bus_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nv04_bus_priv *priv = (void *)object;
|
||||
|
||||
nv_wr32(priv, 0x001100, 0xffffffff);
|
||||
nv_wr32(priv, 0x001140, 0x00000111);
|
||||
|
||||
return nouveau_bus_init(&priv->base);
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv04_bus_oclass = {
|
||||
.handle = NV_SUBDEV(BUS, 0x04),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv04_bus_ctor,
|
||||
.dtor = _nouveau_bus_dtor,
|
||||
.init = nv04_bus_init,
|
||||
.fini = _nouveau_bus_fini,
|
||||
},
|
||||
};
|
112
drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c
Normal file
112
drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2012 Nouveau Community
|
||||
*
|
||||
* 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: Martin Peres <martin.peres@labri.fr>
|
||||
* Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <subdev/bus.h>
|
||||
|
||||
struct nv31_bus_priv {
|
||||
struct nouveau_bus base;
|
||||
};
|
||||
|
||||
static void
|
||||
nv31_bus_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nouveau_bus *pbus = nouveau_bus(subdev);
|
||||
u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
|
||||
u32 gpio = nv_rd32(pbus, 0x001104) & nv_rd32(pbus, 0x001144);
|
||||
|
||||
if (gpio) {
|
||||
subdev = nouveau_subdev(pbus, NVDEV_SUBDEV_GPIO);
|
||||
if (subdev && subdev->intr)
|
||||
subdev->intr(subdev);
|
||||
}
|
||||
|
||||
if (stat & 0x00000008) { /* NV41- */
|
||||
u32 addr = nv_rd32(pbus, 0x009084);
|
||||
u32 data = nv_rd32(pbus, 0x009088);
|
||||
|
||||
nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x\n",
|
||||
(addr & 0x00000002) ? "write" : "read", data,
|
||||
(addr & 0x00fffffc));
|
||||
|
||||
stat &= ~0x00000008;
|
||||
nv_wr32(pbus, 0x001100, 0x00000008);
|
||||
}
|
||||
|
||||
if (stat & 0x00070000) {
|
||||
subdev = nouveau_subdev(pbus, NVDEV_SUBDEV_THERM);
|
||||
if (subdev && subdev->intr)
|
||||
subdev->intr(subdev);
|
||||
stat &= ~0x00070000;
|
||||
nv_wr32(pbus, 0x001100, 0x00070000);
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
nv_error(pbus, "unknown intr 0x%08x\n", stat);
|
||||
nv_mask(pbus, 0x001140, stat, 0x00000000);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nv31_bus_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nv31_bus_priv *priv = (void *)object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_bus_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wr32(priv, 0x001100, 0xffffffff);
|
||||
nv_wr32(priv, 0x001140, 0x00070008);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv31_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv31_bus_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_bus_create(parent, engine, oclass, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->intr = nv31_bus_intr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv31_bus_oclass = {
|
||||
.handle = NV_SUBDEV(BUS, 0x31),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv31_bus_ctor,
|
||||
.dtor = _nouveau_bus_dtor,
|
||||
.init = nv31_bus_init,
|
||||
.fini = _nouveau_bus_fini,
|
||||
},
|
||||
};
|
105
drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c
Normal file
105
drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2012 Nouveau Community
|
||||
*
|
||||
* 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: Martin Peres <martin.peres@labri.fr>
|
||||
* Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <subdev/bus.h>
|
||||
|
||||
struct nv50_bus_priv {
|
||||
struct nouveau_bus base;
|
||||
};
|
||||
|
||||
static void
|
||||
nv50_bus_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nouveau_bus *pbus = nouveau_bus(subdev);
|
||||
u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
|
||||
|
||||
if (stat & 0x00000008) {
|
||||
u32 addr = nv_rd32(pbus, 0x009084);
|
||||
u32 data = nv_rd32(pbus, 0x009088);
|
||||
|
||||
nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x\n",
|
||||
(addr & 0x00000002) ? "write" : "read", data,
|
||||
(addr & 0x00fffffc));
|
||||
|
||||
stat &= ~0x00000008;
|
||||
nv_wr32(pbus, 0x001100, 0x00000008);
|
||||
}
|
||||
|
||||
if (stat & 0x00010000) {
|
||||
subdev = nouveau_subdev(pbus, NVDEV_SUBDEV_THERM);
|
||||
if (subdev && subdev->intr)
|
||||
subdev->intr(subdev);
|
||||
stat &= ~0x00010000;
|
||||
nv_wr32(pbus, 0x001100, 0x00010000);
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
nv_error(pbus, "unknown intr 0x%08x\n", stat);
|
||||
nv_mask(pbus, 0x001140, stat, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_bus_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nv50_bus_priv *priv = (void *)object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_bus_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wr32(priv, 0x001100, 0xffffffff);
|
||||
nv_wr32(priv, 0x001140, 0x00010008);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv50_bus_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_bus_create(parent, engine, oclass, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->intr = nv50_bus_intr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv50_bus_oclass = {
|
||||
.handle = NV_SUBDEV(BUS, 0x50),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv50_bus_ctor,
|
||||
.dtor = _nouveau_bus_dtor,
|
||||
.init = nv50_bus_init,
|
||||
.fini = _nouveau_bus_fini,
|
||||
},
|
||||
};
|
101
drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c
Normal file
101
drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2012 Nouveau Community
|
||||
*
|
||||
* 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: Martin Peres <martin.peres@labri.fr>
|
||||
* Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <subdev/bus.h>
|
||||
|
||||
struct nvc0_bus_priv {
|
||||
struct nouveau_bus base;
|
||||
};
|
||||
|
||||
static void
|
||||
nvc0_bus_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nouveau_bus *pbus = nouveau_bus(subdev);
|
||||
u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
|
||||
|
||||
if (stat & 0x0000000e) {
|
||||
u32 addr = nv_rd32(pbus, 0x009084);
|
||||
u32 data = nv_rd32(pbus, 0x009088);
|
||||
|
||||
nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x [ %s%s%s]\n",
|
||||
(addr & 0x00000002) ? "write" : "read", data,
|
||||
(addr & 0x00fffffc),
|
||||
(stat & 0x00000002) ? "!ENGINE " : "",
|
||||
(stat & 0x00000004) ? "IBUS " : "",
|
||||
(stat & 0x00000008) ? "TIMEOUT " : "");
|
||||
|
||||
nv_wr32(pbus, 0x009084, 0x00000000);
|
||||
nv_wr32(pbus, 0x001100, (stat & 0x0000000e));
|
||||
stat &= ~0x0000000e;
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
nv_error(pbus, "unknown intr 0x%08x\n", stat);
|
||||
nv_mask(pbus, 0x001140, stat, 0x00000000);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_bus_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nvc0_bus_priv *priv = (void *)object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_bus_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wr32(priv, 0x001100, 0xffffffff);
|
||||
nv_wr32(priv, 0x001140, 0x0000000e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nvc0_bus_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_bus_create(parent, engine, oclass, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_subdev(priv)->intr = nvc0_bus_intr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nvc0_bus_oclass = {
|
||||
.handle = NV_SUBDEV(BUS, 0xc0),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nvc0_bus_ctor,
|
||||
.dtor = _nouveau_bus_dtor,
|
||||
.init = nvc0_bus_init,
|
||||
.fini = _nouveau_bus_fini,
|
||||
},
|
||||
};
|
@ -66,6 +66,7 @@ static const u64 disable_map[] = {
|
||||
[NVDEV_SUBDEV_CLOCK] = NV_DEVICE_DISABLE_CORE,
|
||||
[NVDEV_SUBDEV_MXM] = NV_DEVICE_DISABLE_CORE,
|
||||
[NVDEV_SUBDEV_MC] = NV_DEVICE_DISABLE_CORE,
|
||||
[NVDEV_SUBDEV_BUS] = NV_DEVICE_DISABLE_CORE,
|
||||
[NVDEV_SUBDEV_TIMER] = NV_DEVICE_DISABLE_CORE,
|
||||
[NVDEV_SUBDEV_FB] = NV_DEVICE_DISABLE_CORE,
|
||||
[NVDEV_SUBDEV_LTCG] = NV_DEVICE_DISABLE_CORE,
|
||||
@ -103,8 +104,8 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_device *device;
|
||||
struct nouveau_devobj *devobj;
|
||||
struct nv_device_class *args = data;
|
||||
u64 disable, boot0, strap;
|
||||
u64 mmio_base, mmio_size;
|
||||
u32 boot0, strap;
|
||||
u64 disable, mmio_base, mmio_size;
|
||||
void __iomem *map;
|
||||
int ret, i, c;
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <subdev/device.h>
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bus.h>
|
||||
#include <subdev/i2c.h>
|
||||
#include <subdev/clock.h>
|
||||
#include <subdev/devinit.h>
|
||||
@ -46,10 +47,11 @@ nv04_identify(struct nouveau_device *device)
|
||||
case 0x04:
|
||||
device->cname = "NV04";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv04_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv04_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
@ -63,10 +65,11 @@ nv04_identify(struct nouveau_device *device)
|
||||
case 0x05:
|
||||
device->cname = "NV05";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv05_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv04_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <subdev/device.h>
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bus.h>
|
||||
#include <subdev/gpio.h>
|
||||
#include <subdev/i2c.h>
|
||||
#include <subdev/clock.h>
|
||||
@ -48,10 +49,11 @@ nv10_identify(struct nouveau_device *device)
|
||||
device->cname = "NV10";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
@ -64,10 +66,11 @@ nv10_identify(struct nouveau_device *device)
|
||||
device->cname = "NV15";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
@ -82,10 +85,11 @@ nv10_identify(struct nouveau_device *device)
|
||||
device->cname = "NV16";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
@ -100,10 +104,11 @@ nv10_identify(struct nouveau_device *device)
|
||||
device->cname = "nForce";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv1a_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
@ -118,10 +123,11 @@ nv10_identify(struct nouveau_device *device)
|
||||
device->cname = "NV11";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
@ -136,10 +142,11 @@ nv10_identify(struct nouveau_device *device)
|
||||
device->cname = "NV17";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
@ -154,10 +161,11 @@ nv10_identify(struct nouveau_device *device)
|
||||
device->cname = "nForce2";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv1a_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
@ -172,10 +180,11 @@ nv10_identify(struct nouveau_device *device)
|
||||
device->cname = "NV18";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <subdev/device.h>
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bus.h>
|
||||
#include <subdev/gpio.h>
|
||||
#include <subdev/i2c.h>
|
||||
#include <subdev/clock.h>
|
||||
@ -49,10 +50,11 @@ nv20_identify(struct nouveau_device *device)
|
||||
device->cname = "NV20";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
@ -67,10 +69,11 @@ nv20_identify(struct nouveau_device *device)
|
||||
device->cname = "NV25";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv25_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
@ -85,10 +88,11 @@ nv20_identify(struct nouveau_device *device)
|
||||
device->cname = "NV28";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv25_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
@ -103,10 +107,11 @@ nv20_identify(struct nouveau_device *device)
|
||||
device->cname = "NV2A";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv25_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <subdev/device.h>
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bus.h>
|
||||
#include <subdev/gpio.h>
|
||||
#include <subdev/i2c.h>
|
||||
#include <subdev/clock.h>
|
||||
@ -49,10 +50,11 @@ nv30_identify(struct nouveau_device *device)
|
||||
device->cname = "NV30";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
@ -67,10 +69,11 @@ nv30_identify(struct nouveau_device *device)
|
||||
device->cname = "NV35";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv35_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
@ -85,10 +88,11 @@ nv30_identify(struct nouveau_device *device)
|
||||
device->cname = "NV31";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
@ -104,10 +108,11 @@ nv30_identify(struct nouveau_device *device)
|
||||
device->cname = "NV36";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv36_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
@ -123,10 +128,11 @@ nv30_identify(struct nouveau_device *device)
|
||||
device->cname = "NV34";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
|
||||
|
@ -24,6 +24,8 @@
|
||||
|
||||
#include <subdev/device.h>
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bus.h>
|
||||
#include <subdev/vm.h>
|
||||
#include <subdev/gpio.h>
|
||||
#include <subdev/i2c.h>
|
||||
#include <subdev/clock.h>
|
||||
@ -50,11 +52,12 @@ nv40_identify(struct nouveau_device *device)
|
||||
device->cname = "NV40";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
|
||||
@ -70,11 +73,12 @@ nv40_identify(struct nouveau_device *device)
|
||||
device->cname = "NV41";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv41_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
|
||||
@ -90,11 +94,12 @@ nv40_identify(struct nouveau_device *device)
|
||||
device->cname = "NV42";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv41_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
|
||||
@ -110,11 +115,12 @@ nv40_identify(struct nouveau_device *device)
|
||||
device->cname = "NV43";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv41_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
|
||||
@ -130,11 +136,12 @@ nv40_identify(struct nouveau_device *device)
|
||||
device->cname = "NV45";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
|
||||
@ -150,11 +157,12 @@ nv40_identify(struct nouveau_device *device)
|
||||
device->cname = "G70";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv47_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
|
||||
@ -170,11 +178,12 @@ nv40_identify(struct nouveau_device *device)
|
||||
device->cname = "G71";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv49_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
|
||||
@ -190,11 +199,12 @@ nv40_identify(struct nouveau_device *device)
|
||||
device->cname = "G73";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv49_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
|
||||
@ -210,11 +220,12 @@ nv40_identify(struct nouveau_device *device)
|
||||
device->cname = "NV44";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv44_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
|
||||
@ -230,11 +241,12 @@ nv40_identify(struct nouveau_device *device)
|
||||
device->cname = "G72";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
|
||||
@ -250,11 +262,12 @@ nv40_identify(struct nouveau_device *device)
|
||||
device->cname = "NV44A";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv44_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
|
||||
@ -270,11 +283,12 @@ nv40_identify(struct nouveau_device *device)
|
||||
device->cname = "C61";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
|
||||
@ -290,11 +304,12 @@ nv40_identify(struct nouveau_device *device)
|
||||
device->cname = "C51";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv4e_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv4e_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
|
||||
@ -310,11 +325,12 @@ nv40_identify(struct nouveau_device *device)
|
||||
device->cname = "C73";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
|
||||
@ -330,11 +346,12 @@ nv40_identify(struct nouveau_device *device)
|
||||
device->cname = "C67";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
|
||||
@ -350,11 +367,12 @@ nv40_identify(struct nouveau_device *device)
|
||||
device->cname = "C68";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <subdev/device.h>
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bus.h>
|
||||
#include <subdev/gpio.h>
|
||||
#include <subdev/i2c.h>
|
||||
#include <subdev/clock.h>
|
||||
@ -57,12 +58,13 @@ nv50_identify(struct nouveau_device *device)
|
||||
device->cname = "G80";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
|
||||
@ -79,12 +81,13 @@ nv50_identify(struct nouveau_device *device)
|
||||
device->cname = "G84";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
|
||||
@ -104,12 +107,13 @@ nv50_identify(struct nouveau_device *device)
|
||||
device->cname = "G86";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
|
||||
@ -129,12 +133,13 @@ nv50_identify(struct nouveau_device *device)
|
||||
device->cname = "G92";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
|
||||
@ -154,12 +159,13 @@ nv50_identify(struct nouveau_device *device)
|
||||
device->cname = "G94";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
|
||||
@ -179,12 +185,13 @@ nv50_identify(struct nouveau_device *device)
|
||||
device->cname = "G96";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
|
||||
@ -204,12 +211,13 @@ nv50_identify(struct nouveau_device *device)
|
||||
device->cname = "G98";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
|
||||
@ -229,12 +237,13 @@ nv50_identify(struct nouveau_device *device)
|
||||
device->cname = "G200";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
|
||||
@ -254,12 +263,13 @@ nv50_identify(struct nouveau_device *device)
|
||||
device->cname = "MCP77/MCP78";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
|
||||
@ -279,12 +289,13 @@ nv50_identify(struct nouveau_device *device)
|
||||
device->cname = "MCP79/MCP7A";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
|
||||
@ -304,12 +315,13 @@ nv50_identify(struct nouveau_device *device)
|
||||
device->cname = "GT215";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
|
||||
@ -330,12 +342,13 @@ nv50_identify(struct nouveau_device *device)
|
||||
device->cname = "GT216";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
|
||||
@ -355,12 +368,13 @@ nv50_identify(struct nouveau_device *device)
|
||||
device->cname = "GT218";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
|
||||
@ -380,12 +394,13 @@ nv50_identify(struct nouveau_device *device)
|
||||
device->cname = "MCP89";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <subdev/device.h>
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bus.h>
|
||||
#include <subdev/gpio.h>
|
||||
#include <subdev/i2c.h>
|
||||
#include <subdev/clock.h>
|
||||
@ -57,12 +58,13 @@ nvc0_identify(struct nouveau_device *device)
|
||||
device->cname = "GF100";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass;
|
||||
@ -85,12 +87,13 @@ nvc0_identify(struct nouveau_device *device)
|
||||
device->cname = "GF104";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass;
|
||||
@ -113,12 +116,13 @@ nvc0_identify(struct nouveau_device *device)
|
||||
device->cname = "GF106";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass;
|
||||
@ -141,12 +145,13 @@ nvc0_identify(struct nouveau_device *device)
|
||||
device->cname = "GF114";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass;
|
||||
@ -169,12 +174,13 @@ nvc0_identify(struct nouveau_device *device)
|
||||
device->cname = "GF116";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass;
|
||||
@ -197,12 +203,13 @@ nvc0_identify(struct nouveau_device *device)
|
||||
device->cname = "GF108";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass;
|
||||
@ -225,12 +232,13 @@ nvc0_identify(struct nouveau_device *device)
|
||||
device->cname = "GF110";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass;
|
||||
@ -253,12 +261,13 @@ nvc0_identify(struct nouveau_device *device)
|
||||
device->cname = "GF119";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass;
|
||||
@ -282,4 +291,4 @@ nvc0_identify(struct nouveau_device *device)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <subdev/device.h>
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bus.h>
|
||||
#include <subdev/gpio.h>
|
||||
#include <subdev/i2c.h>
|
||||
#include <subdev/clock.h>
|
||||
@ -56,13 +57,14 @@ nve0_identify(struct nouveau_device *device)
|
||||
case 0xe4:
|
||||
device->cname = "GK104";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass;
|
||||
@ -84,13 +86,14 @@ nve0_identify(struct nouveau_device *device)
|
||||
case 0xe7:
|
||||
device->cname = "GK107";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass;
|
||||
@ -112,13 +115,14 @@ nve0_identify(struct nouveau_device *device)
|
||||
case 0xe6:
|
||||
device->cname = "GK106";
|
||||
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass;
|
||||
device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass;
|
||||
|
@ -78,12 +78,13 @@ nv50_devinit_init(struct nouveau_object *object)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* if we ran the init tables, execute first script pointer for each
|
||||
* display table output entry that has a matching dcb entry.
|
||||
/* if we ran the init tables, we have to execute the first script
|
||||
* pointer of each dcb entry's display encoder table in order
|
||||
* to properly initialise each encoder.
|
||||
*/
|
||||
while (priv->base.post && ver) {
|
||||
u16 data = nvbios_outp_parse(bios, i++, &ver, &hdr, &cnt, &len, &info);
|
||||
if (data && dcb_outp_match(bios, info.type, info.mask, &ver, &len, &outp)) {
|
||||
while (priv->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) {
|
||||
if (nvbios_outp_match(bios, outp.hasht, outp.hashm,
|
||||
&ver, &hdr, &cnt, &len, &info)) {
|
||||
struct nvbios_init init = {
|
||||
.subdev = nv_subdev(priv),
|
||||
.bios = bios,
|
||||
@ -95,7 +96,8 @@ nv50_devinit_init(struct nouveau_object *object)
|
||||
|
||||
nvbios_exec(&init);
|
||||
}
|
||||
};
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -22,8 +22,10 @@
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/object.h>
|
||||
#include <core/client.h>
|
||||
#include <core/enum.h>
|
||||
#include <core/engctx.h>
|
||||
#include <core/object.h>
|
||||
|
||||
#include <subdev/fb.h>
|
||||
#include <subdev/bios.h>
|
||||
@ -302,17 +304,18 @@ static const struct nouveau_enum vm_client[] = {
|
||||
};
|
||||
|
||||
static const struct nouveau_enum vm_engine[] = {
|
||||
{ 0x00000000, "PGRAPH", NULL },
|
||||
{ 0x00000001, "PVP", NULL },
|
||||
{ 0x00000000, "PGRAPH", NULL, NVDEV_ENGINE_GR },
|
||||
{ 0x00000001, "PVP", NULL, NVDEV_ENGINE_VP },
|
||||
{ 0x00000004, "PEEPHOLE", NULL },
|
||||
{ 0x00000005, "PFIFO", vm_pfifo_subclients },
|
||||
{ 0x00000005, "PFIFO", vm_pfifo_subclients, NVDEV_ENGINE_FIFO },
|
||||
{ 0x00000006, "BAR", vm_bar_subclients },
|
||||
{ 0x00000008, "PPPP", NULL },
|
||||
{ 0x00000009, "PBSP", NULL },
|
||||
{ 0x0000000a, "PCRYPT", NULL },
|
||||
{ 0x00000008, "PPPP", NULL, NVDEV_ENGINE_PPP },
|
||||
{ 0x00000008, "PMPEG", NULL, NVDEV_ENGINE_MPEG },
|
||||
{ 0x00000009, "PBSP", NULL, NVDEV_ENGINE_BSP },
|
||||
{ 0x0000000a, "PCRYPT", NULL, NVDEV_ENGINE_CRYPT },
|
||||
{ 0x0000000b, "PCOUNTER", NULL },
|
||||
{ 0x0000000c, "SEMAPHORE_BG", NULL },
|
||||
{ 0x0000000d, "PCOPY", NULL },
|
||||
{ 0x0000000d, "PCOPY", NULL, NVDEV_ENGINE_COPY0 },
|
||||
{ 0x0000000e, "PDAEMON", NULL },
|
||||
{}
|
||||
};
|
||||
@ -334,8 +337,10 @@ static void
|
||||
nv50_fb_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nouveau_device *device = nv_device(subdev);
|
||||
struct nouveau_engine *engine;
|
||||
struct nv50_fb_priv *priv = (void *)subdev;
|
||||
const struct nouveau_enum *en, *cl;
|
||||
struct nouveau_object *engctx = NULL;
|
||||
u32 trap[6], idx, chan;
|
||||
u8 st0, st1, st2, st3;
|
||||
int i;
|
||||
@ -366,36 +371,55 @@ nv50_fb_intr(struct nouveau_subdev *subdev)
|
||||
}
|
||||
chan = (trap[2] << 16) | trap[1];
|
||||
|
||||
nv_error(priv, "trapped %s at 0x%02x%04x%04x on channel 0x%08x ",
|
||||
(trap[5] & 0x00000100) ? "read" : "write",
|
||||
trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan);
|
||||
|
||||
en = nouveau_enum_find(vm_engine, st0);
|
||||
|
||||
if (en && en->data2) {
|
||||
const struct nouveau_enum *orig_en = en;
|
||||
while (en->name && en->value == st0 && en->data2) {
|
||||
engine = nouveau_engine(subdev, en->data2);
|
||||
if (engine) {
|
||||
engctx = nouveau_engctx_get(engine, chan);
|
||||
if (engctx)
|
||||
break;
|
||||
}
|
||||
en++;
|
||||
}
|
||||
if (!engctx)
|
||||
en = orig_en;
|
||||
}
|
||||
|
||||
nv_error(priv, "trapped %s at 0x%02x%04x%04x on channel 0x%08x [%s] ",
|
||||
(trap[5] & 0x00000100) ? "read" : "write",
|
||||
trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan,
|
||||
nouveau_client_name(engctx));
|
||||
|
||||
nouveau_engctx_put(engctx);
|
||||
|
||||
if (en)
|
||||
printk("%s/", en->name);
|
||||
pr_cont("%s/", en->name);
|
||||
else
|
||||
printk("%02x/", st0);
|
||||
pr_cont("%02x/", st0);
|
||||
|
||||
cl = nouveau_enum_find(vm_client, st2);
|
||||
if (cl)
|
||||
printk("%s/", cl->name);
|
||||
pr_cont("%s/", cl->name);
|
||||
else
|
||||
printk("%02x/", st2);
|
||||
pr_cont("%02x/", st2);
|
||||
|
||||
if (cl && cl->data) cl = nouveau_enum_find(cl->data, st3);
|
||||
else if (en && en->data) cl = nouveau_enum_find(en->data, st3);
|
||||
else cl = NULL;
|
||||
if (cl)
|
||||
printk("%s", cl->name);
|
||||
pr_cont("%s", cl->name);
|
||||
else
|
||||
printk("%02x", st3);
|
||||
pr_cont("%02x", st3);
|
||||
|
||||
printk(" reason: ");
|
||||
pr_cont(" reason: ");
|
||||
en = nouveau_enum_find(vm_fault, st1);
|
||||
if (en)
|
||||
printk("%s\n", en->name);
|
||||
pr_cont("%s\n", en->name);
|
||||
else
|
||||
printk("0x%08x\n", st1);
|
||||
pr_cont("0x%08x\n", st1);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -102,135 +102,19 @@ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nouveau_gpio_irq(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, bool on)
|
||||
void
|
||||
_nouveau_gpio_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct dcb_gpio_func func;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
|
||||
if (ret == 0) {
|
||||
if (idx == 0 && gpio->irq_enable)
|
||||
gpio->irq_enable(gpio, func.line, on);
|
||||
else
|
||||
ret = -ENODEV;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct gpio_isr {
|
||||
struct nouveau_gpio *gpio;
|
||||
struct list_head head;
|
||||
struct work_struct work;
|
||||
int idx;
|
||||
struct dcb_gpio_func func;
|
||||
void (*handler)(void *, int);
|
||||
void *data;
|
||||
bool inhibit;
|
||||
};
|
||||
|
||||
static void
|
||||
nouveau_gpio_isr_bh(struct work_struct *work)
|
||||
{
|
||||
struct gpio_isr *isr = container_of(work, struct gpio_isr, work);
|
||||
struct nouveau_gpio *gpio = isr->gpio;
|
||||
unsigned long flags;
|
||||
int state;
|
||||
|
||||
state = nouveau_gpio_get(gpio, isr->idx, isr->func.func,
|
||||
isr->func.line);
|
||||
if (state >= 0)
|
||||
isr->handler(isr->data, state);
|
||||
|
||||
spin_lock_irqsave(&gpio->lock, flags);
|
||||
isr->inhibit = false;
|
||||
spin_unlock_irqrestore(&gpio->lock, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
nouveau_gpio_isr_run(struct nouveau_gpio *gpio, int idx, u32 line_mask)
|
||||
{
|
||||
struct gpio_isr *isr;
|
||||
|
||||
if (idx != 0)
|
||||
return;
|
||||
|
||||
spin_lock(&gpio->lock);
|
||||
list_for_each_entry(isr, &gpio->isr, head) {
|
||||
if (line_mask & (1 << isr->func.line)) {
|
||||
if (isr->inhibit)
|
||||
continue;
|
||||
isr->inhibit = true;
|
||||
schedule_work(&isr->work);
|
||||
}
|
||||
}
|
||||
spin_unlock(&gpio->lock);
|
||||
}
|
||||
|
||||
static int
|
||||
nouveau_gpio_isr_add(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
|
||||
void (*handler)(void *, int), void *data)
|
||||
{
|
||||
struct gpio_isr *isr;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
isr = kzalloc(sizeof(*isr), GFP_KERNEL);
|
||||
if (!isr)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = nouveau_gpio_find(gpio, idx, tag, line, &isr->func);
|
||||
if (ret) {
|
||||
kfree(isr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
INIT_WORK(&isr->work, nouveau_gpio_isr_bh);
|
||||
isr->gpio = gpio;
|
||||
isr->handler = handler;
|
||||
isr->data = data;
|
||||
isr->idx = idx;
|
||||
|
||||
spin_lock_irqsave(&gpio->lock, flags);
|
||||
list_add(&isr->head, &gpio->isr);
|
||||
spin_unlock_irqrestore(&gpio->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nouveau_gpio_isr_del(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
|
||||
void (*handler)(void *, int), void *data)
|
||||
{
|
||||
struct gpio_isr *isr, *tmp;
|
||||
struct dcb_gpio_func func;
|
||||
unsigned long flags;
|
||||
LIST_HEAD(tofree);
|
||||
int ret;
|
||||
|
||||
ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
|
||||
if (ret == 0) {
|
||||
spin_lock_irqsave(&gpio->lock, flags);
|
||||
list_for_each_entry_safe(isr, tmp, &gpio->isr, head) {
|
||||
if (memcmp(&isr->func, &func, sizeof(func)) ||
|
||||
isr->idx != idx ||
|
||||
isr->handler != handler || isr->data != data)
|
||||
continue;
|
||||
list_move_tail(&isr->head, &tofree);
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio->lock, flags);
|
||||
|
||||
list_for_each_entry_safe(isr, tmp, &tofree, head) {
|
||||
flush_work(&isr->work);
|
||||
kfree(isr);
|
||||
}
|
||||
}
|
||||
struct nouveau_gpio *gpio = (void *)object;
|
||||
nouveau_event_destroy(&gpio->events);
|
||||
nouveau_subdev_destroy(&gpio->base);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_gpio_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, int length, void **pobject)
|
||||
struct nouveau_oclass *oclass, int lines,
|
||||
int length, void **pobject)
|
||||
{
|
||||
struct nouveau_gpio *gpio;
|
||||
int ret;
|
||||
@ -241,15 +125,13 @@ nouveau_gpio_create_(struct nouveau_object *parent,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nouveau_event_create(lines, &gpio->events);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
gpio->find = nouveau_gpio_find;
|
||||
gpio->set = nouveau_gpio_set;
|
||||
gpio->get = nouveau_gpio_get;
|
||||
gpio->irq = nouveau_gpio_irq;
|
||||
gpio->isr_run = nouveau_gpio_isr_run;
|
||||
gpio->isr_add = nouveau_gpio_isr_add;
|
||||
gpio->isr_del = nouveau_gpio_isr_del;
|
||||
INIT_LIST_HEAD(&gpio->isr);
|
||||
spin_lock_init(&gpio->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <subdev/gpio.h>
|
||||
#include "priv.h"
|
||||
|
||||
struct nv10_gpio_priv {
|
||||
struct nouveau_gpio base;
|
||||
@ -82,15 +82,6 @@ nv10_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nv10_gpio_irq_enable(struct nouveau_gpio *gpio, int line, bool on)
|
||||
{
|
||||
u32 mask = 0x00010001 << line;
|
||||
|
||||
nv_wr32(gpio, 0x001104, mask);
|
||||
nv_mask(gpio, 0x001144, mask, on ? mask : 0);
|
||||
}
|
||||
|
||||
static void
|
||||
nv10_gpio_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
@ -98,12 +89,30 @@ nv10_gpio_intr(struct nouveau_subdev *subdev)
|
||||
u32 intr = nv_rd32(priv, 0x001104);
|
||||
u32 hi = (intr & 0x0000ffff) >> 0;
|
||||
u32 lo = (intr & 0xffff0000) >> 16;
|
||||
int i;
|
||||
|
||||
priv->base.isr_run(&priv->base, 0, hi | lo);
|
||||
for (i = 0; (hi | lo) && i < 32; i++) {
|
||||
if ((hi | lo) & (1 << i))
|
||||
nouveau_event_trigger(priv->base.events, i);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x001104, intr);
|
||||
}
|
||||
|
||||
static void
|
||||
nv10_gpio_intr_enable(struct nouveau_event *event, int line)
|
||||
{
|
||||
nv_wr32(event->priv, 0x001104, 0x00010001 << line);
|
||||
nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00010001 << line);
|
||||
}
|
||||
|
||||
static void
|
||||
nv10_gpio_intr_disable(struct nouveau_event *event, int line)
|
||||
{
|
||||
nv_wr32(event->priv, 0x001104, 0x00010001 << line);
|
||||
nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00000000);
|
||||
}
|
||||
|
||||
static int
|
||||
nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
@ -112,14 +121,16 @@ nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nv10_gpio_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_gpio_create(parent, engine, oclass, &priv);
|
||||
ret = nouveau_gpio_create(parent, engine, oclass, 16, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->base.drive = nv10_gpio_drive;
|
||||
priv->base.sense = nv10_gpio_sense;
|
||||
priv->base.irq_enable = nv10_gpio_irq_enable;
|
||||
priv->base.events->priv = priv;
|
||||
priv->base.events->enable = nv10_gpio_intr_enable;
|
||||
priv->base.events->disable = nv10_gpio_intr_disable;
|
||||
nv_subdev(priv)->intr = nv10_gpio_intr;
|
||||
return 0;
|
||||
}
|
||||
@ -141,8 +152,6 @@ nv10_gpio_init(struct nouveau_object *object)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wr32(priv, 0x001140, 0x00000000);
|
||||
nv_wr32(priv, 0x001100, 0xffffffff);
|
||||
nv_wr32(priv, 0x001144, 0x00000000);
|
||||
nv_wr32(priv, 0x001104, 0xffffffff);
|
||||
return 0;
|
||||
@ -152,7 +161,6 @@ static int
|
||||
nv10_gpio_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
struct nv10_gpio_priv *priv = (void *)object;
|
||||
nv_wr32(priv, 0x001140, 0x00000000);
|
||||
nv_wr32(priv, 0x001144, 0x00000000);
|
||||
return nouveau_gpio_fini(&priv->base, suspend);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <subdev/gpio.h>
|
||||
#include "priv.h"
|
||||
|
||||
struct nv50_gpio_priv {
|
||||
struct nouveau_gpio base;
|
||||
@ -94,22 +94,13 @@ nv50_gpio_sense(struct nouveau_gpio *gpio, int line)
|
||||
return !!(nv_rd32(gpio, reg) & (4 << shift));
|
||||
}
|
||||
|
||||
void
|
||||
nv50_gpio_irq_enable(struct nouveau_gpio *gpio, int line, bool on)
|
||||
{
|
||||
u32 reg = line < 16 ? 0xe050 : 0xe070;
|
||||
u32 mask = 0x00010001 << (line & 0xf);
|
||||
|
||||
nv_wr32(gpio, reg + 4, mask);
|
||||
nv_mask(gpio, reg + 0, mask, on ? mask : 0);
|
||||
}
|
||||
|
||||
void
|
||||
nv50_gpio_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nv50_gpio_priv *priv = (void *)subdev;
|
||||
u32 intr0, intr1 = 0;
|
||||
u32 hi, lo;
|
||||
int i;
|
||||
|
||||
intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050);
|
||||
if (nv_device(priv)->chipset >= 0x90)
|
||||
@ -117,13 +108,35 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
|
||||
|
||||
hi = (intr0 & 0x0000ffff) | (intr1 << 16);
|
||||
lo = (intr0 >> 16) | (intr1 & 0xffff0000);
|
||||
priv->base.isr_run(&priv->base, 0, hi | lo);
|
||||
|
||||
for (i = 0; (hi | lo) && i < 32; i++) {
|
||||
if ((hi | lo) & (1 << i))
|
||||
nouveau_event_trigger(priv->base.events, i);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0xe054, intr0);
|
||||
if (nv_device(priv)->chipset >= 0x90)
|
||||
nv_wr32(priv, 0xe074, intr1);
|
||||
}
|
||||
|
||||
void
|
||||
nv50_gpio_intr_enable(struct nouveau_event *event, int line)
|
||||
{
|
||||
const u32 addr = line < 16 ? 0xe050 : 0xe070;
|
||||
const u32 mask = 0x00010001 << (line & 0xf);
|
||||
nv_wr32(event->priv, addr + 0x04, mask);
|
||||
nv_mask(event->priv, addr + 0x00, mask, mask);
|
||||
}
|
||||
|
||||
void
|
||||
nv50_gpio_intr_disable(struct nouveau_event *event, int line)
|
||||
{
|
||||
const u32 addr = line < 16 ? 0xe050 : 0xe070;
|
||||
const u32 mask = 0x00010001 << (line & 0xf);
|
||||
nv_wr32(event->priv, addr + 0x04, mask);
|
||||
nv_mask(event->priv, addr + 0x00, mask, 0x00000000);
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
@ -132,7 +145,9 @@ nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nv50_gpio_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_gpio_create(parent, engine, oclass, &priv);
|
||||
ret = nouveau_gpio_create(parent, engine, oclass,
|
||||
nv_device(parent)->chipset >= 0x90 ? 32 : 16,
|
||||
&priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -140,7 +155,9 @@ nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
priv->base.reset = nv50_gpio_reset;
|
||||
priv->base.drive = nv50_gpio_drive;
|
||||
priv->base.sense = nv50_gpio_sense;
|
||||
priv->base.irq_enable = nv50_gpio_irq_enable;
|
||||
priv->base.events->priv = priv;
|
||||
priv->base.events->enable = nv50_gpio_intr_enable;
|
||||
priv->base.events->disable = nv50_gpio_intr_disable;
|
||||
nv_subdev(priv)->intr = nv50_gpio_intr;
|
||||
return 0;
|
||||
}
|
||||
|
@ -22,13 +22,13 @@
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <subdev/gpio.h>
|
||||
#include "priv.h"
|
||||
|
||||
struct nvd0_gpio_priv {
|
||||
struct nouveau_gpio base;
|
||||
};
|
||||
|
||||
static void
|
||||
void
|
||||
nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match)
|
||||
{
|
||||
struct nouveau_bios *bios = nouveau_bios(gpio);
|
||||
@ -57,7 +57,7 @@ nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
nvd0_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
|
||||
{
|
||||
u32 data = ((dir ^ 1) << 13) | (out << 12);
|
||||
@ -66,7 +66,7 @@ nvd0_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
nvd0_gpio_sense(struct nouveau_gpio *gpio, int line)
|
||||
{
|
||||
return !!(nv_rd32(gpio, 0x00d610 + (line * 4)) & 0x00004000);
|
||||
@ -80,7 +80,7 @@ nvd0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nvd0_gpio_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_gpio_create(parent, engine, oclass, &priv);
|
||||
ret = nouveau_gpio_create(parent, engine, oclass, 32, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -88,7 +88,9 @@ nvd0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
priv->base.reset = nvd0_gpio_reset;
|
||||
priv->base.drive = nvd0_gpio_drive;
|
||||
priv->base.sense = nvd0_gpio_sense;
|
||||
priv->base.irq_enable = nv50_gpio_irq_enable;
|
||||
priv->base.events->priv = priv;
|
||||
priv->base.events->enable = nv50_gpio_intr_enable;
|
||||
priv->base.events->disable = nv50_gpio_intr_disable;
|
||||
nv_subdev(priv)->intr = nv50_gpio_intr;
|
||||
return 0;
|
||||
}
|
||||
|
131
drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c
Normal file
131
drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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 "priv.h"
|
||||
|
||||
struct nve0_gpio_priv {
|
||||
struct nouveau_gpio base;
|
||||
};
|
||||
|
||||
void
|
||||
nve0_gpio_intr(struct nouveau_subdev *subdev)
|
||||
{
|
||||
struct nve0_gpio_priv *priv = (void *)subdev;
|
||||
u32 intr0 = nv_rd32(priv, 0xdc00) & nv_rd32(priv, 0xdc08);
|
||||
u32 intr1 = nv_rd32(priv, 0xdc80) & nv_rd32(priv, 0xdc88);
|
||||
u32 hi = (intr0 & 0x0000ffff) | (intr1 << 16);
|
||||
u32 lo = (intr0 >> 16) | (intr1 & 0xffff0000);
|
||||
int i;
|
||||
|
||||
for (i = 0; (hi | lo) && i < 32; i++) {
|
||||
if ((hi | lo) & (1 << i))
|
||||
nouveau_event_trigger(priv->base.events, i);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0xdc00, intr0);
|
||||
nv_wr32(priv, 0xdc88, intr1);
|
||||
}
|
||||
|
||||
void
|
||||
nve0_gpio_intr_enable(struct nouveau_event *event, int line)
|
||||
{
|
||||
const u32 addr = line < 16 ? 0xdc00 : 0xdc80;
|
||||
const u32 mask = 0x00010001 << (line & 0xf);
|
||||
nv_wr32(event->priv, addr + 0x08, mask);
|
||||
nv_mask(event->priv, addr + 0x00, mask, mask);
|
||||
}
|
||||
|
||||
void
|
||||
nve0_gpio_intr_disable(struct nouveau_event *event, int line)
|
||||
{
|
||||
const u32 addr = line < 16 ? 0xdc00 : 0xdc80;
|
||||
const u32 mask = 0x00010001 << (line & 0xf);
|
||||
nv_wr32(event->priv, addr + 0x08, mask);
|
||||
nv_mask(event->priv, addr + 0x00, mask, 0x00000000);
|
||||
}
|
||||
|
||||
int
|
||||
nve0_gpio_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
struct nve0_gpio_priv *priv = (void *)object;
|
||||
nv_wr32(priv, 0xdc08, 0x00000000);
|
||||
nv_wr32(priv, 0xdc88, 0x00000000);
|
||||
return nouveau_gpio_fini(&priv->base, suspend);
|
||||
}
|
||||
|
||||
int
|
||||
nve0_gpio_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nve0_gpio_priv *priv = (void *)object;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_gpio_init(&priv->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nv_wr32(priv, 0xdc00, 0xffffffff);
|
||||
nv_wr32(priv, 0xdc80, 0xffffffff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nve0_gpio_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nve0_gpio_priv *priv = (void *)object;
|
||||
nouveau_gpio_destroy(&priv->base);
|
||||
}
|
||||
|
||||
static int
|
||||
nve0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nve0_gpio_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_gpio_create(parent, engine, oclass, 32, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->base.reset = nvd0_gpio_reset;
|
||||
priv->base.drive = nvd0_gpio_drive;
|
||||
priv->base.sense = nvd0_gpio_sense;
|
||||
priv->base.events->priv = priv;
|
||||
priv->base.events->enable = nve0_gpio_intr_enable;
|
||||
priv->base.events->disable = nve0_gpio_intr_disable;
|
||||
nv_subdev(priv)->intr = nve0_gpio_intr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nve0_gpio_oclass = {
|
||||
.handle = NV_SUBDEV(GPIO, 0xe0),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nve0_gpio_ctor,
|
||||
.dtor = nv50_gpio_dtor,
|
||||
.init = nve0_gpio_init,
|
||||
.fini = nve0_gpio_fini,
|
||||
},
|
||||
};
|
17
drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h
Normal file
17
drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef __NVKM_GPIO_H__
|
||||
#define __NVKM_GPIO_H__
|
||||
|
||||
#include <subdev/gpio.h>
|
||||
|
||||
void nv50_gpio_dtor(struct nouveau_object *);
|
||||
int nv50_gpio_init(struct nouveau_object *);
|
||||
int nv50_gpio_fini(struct nouveau_object *, bool);
|
||||
void nv50_gpio_intr(struct nouveau_subdev *);
|
||||
void nv50_gpio_intr_enable(struct nouveau_event *, int line);
|
||||
void nv50_gpio_intr_disable(struct nouveau_event *, int line);
|
||||
|
||||
void nvd0_gpio_reset(struct nouveau_gpio *, u8);
|
||||
int nvd0_gpio_drive(struct nouveau_gpio *, int, int, int);
|
||||
int nvd0_gpio_sense(struct nouveau_gpio *, int);
|
||||
|
||||
#endif
|
279
drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c
Normal file
279
drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright 2013 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 <bskeggs@redhat.com>
|
||||
*/
|
||||
|
||||
#include <subdev/i2c.h>
|
||||
|
||||
struct anx9805_i2c_port {
|
||||
struct nouveau_i2c_port base;
|
||||
u32 addr;
|
||||
u32 ctrl;
|
||||
};
|
||||
|
||||
static int
|
||||
anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh)
|
||||
{
|
||||
struct anx9805_i2c_port *chan = (void *)port;
|
||||
struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent;
|
||||
u8 tmp, i;
|
||||
|
||||
nv_wri2cr(mast, chan->addr, 0xa0, link_bw);
|
||||
nv_wri2cr(mast, chan->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00));
|
||||
nv_wri2cr(mast, chan->addr, 0xa2, 0x01);
|
||||
nv_wri2cr(mast, chan->addr, 0xa8, 0x01);
|
||||
|
||||
i = 0;
|
||||
while ((tmp = nv_rdi2cr(mast, chan->addr, 0xa8)) & 0x01) {
|
||||
mdelay(5);
|
||||
if (i++ == 100) {
|
||||
nv_error(port, "link training timed out\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp & 0x70) {
|
||||
nv_error(port, "link training failed: 0x%02x\n", tmp);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
anx9805_aux(struct nouveau_i2c_port *port, u8 type, u32 addr, u8 *data, u8 size)
|
||||
{
|
||||
struct anx9805_i2c_port *chan = (void *)port;
|
||||
struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent;
|
||||
int i, ret = -ETIMEDOUT;
|
||||
u8 tmp;
|
||||
|
||||
tmp = nv_rdi2cr(mast, chan->ctrl, 0x07) & ~0x04;
|
||||
nv_wri2cr(mast, chan->ctrl, 0x07, tmp | 0x04);
|
||||
nv_wri2cr(mast, chan->ctrl, 0x07, tmp);
|
||||
nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01);
|
||||
|
||||
nv_wri2cr(mast, chan->addr, 0xe4, 0x80);
|
||||
for (i = 0; !(type & 1) && i < size; i++)
|
||||
nv_wri2cr(mast, chan->addr, 0xf0 + i, data[i]);
|
||||
nv_wri2cr(mast, chan->addr, 0xe5, ((size - 1) << 4) | type);
|
||||
nv_wri2cr(mast, chan->addr, 0xe6, (addr & 0x000ff) >> 0);
|
||||
nv_wri2cr(mast, chan->addr, 0xe7, (addr & 0x0ff00) >> 8);
|
||||
nv_wri2cr(mast, chan->addr, 0xe8, (addr & 0xf0000) >> 16);
|
||||
nv_wri2cr(mast, chan->addr, 0xe9, 0x01);
|
||||
|
||||
i = 0;
|
||||
while ((tmp = nv_rdi2cr(mast, chan->addr, 0xe9)) & 0x01) {
|
||||
mdelay(5);
|
||||
if (i++ == 32)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((tmp = nv_rdi2cr(mast, chan->ctrl, 0xf7)) & 0x01) {
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0; (type & 1) && i < size; i++)
|
||||
data[i] = nv_rdi2cr(mast, chan->addr, 0xf0 + i);
|
||||
ret = 0;
|
||||
done:
|
||||
nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct nouveau_i2c_func
|
||||
anx9805_aux_func = {
|
||||
.aux = anx9805_aux,
|
||||
.lnk_ctl = anx9805_train,
|
||||
};
|
||||
|
||||
static int
|
||||
anx9805_aux_chan_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 index,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_i2c_port *mast = (void *)parent;
|
||||
struct anx9805_i2c_port *chan;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_i2c_port_create(parent, engine, oclass, index,
|
||||
&nouveau_i2c_aux_algo, &chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch ((oclass->handle & 0xff00) >> 8) {
|
||||
case 0x0d:
|
||||
chan->addr = 0x38;
|
||||
chan->ctrl = 0x39;
|
||||
break;
|
||||
case 0x0e:
|
||||
chan->addr = 0x3c;
|
||||
chan->ctrl = 0x3b;
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
}
|
||||
|
||||
if (mast->adapter.algo == &i2c_bit_algo) {
|
||||
struct i2c_algo_bit_data *algo = mast->adapter.algo_data;
|
||||
algo->udelay = max(algo->udelay, 40);
|
||||
}
|
||||
|
||||
chan->base.func = &anx9805_aux_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
anx9805_aux_ofuncs = {
|
||||
.ctor = anx9805_aux_chan_ctor,
|
||||
.dtor = _nouveau_i2c_port_dtor,
|
||||
.init = _nouveau_i2c_port_init,
|
||||
.fini = _nouveau_i2c_port_fini,
|
||||
};
|
||||
|
||||
static int
|
||||
anx9805_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct anx9805_i2c_port *port = adap->algo_data;
|
||||
struct nouveau_i2c_port *mast = (void *)nv_object(port)->parent;
|
||||
struct i2c_msg *msg = msgs;
|
||||
int ret = -ETIMEDOUT;
|
||||
int i, j, cnt = num;
|
||||
u8 seg = 0x00, off = 0x00, tmp;
|
||||
|
||||
tmp = nv_rdi2cr(mast, port->ctrl, 0x07) & ~0x10;
|
||||
nv_wri2cr(mast, port->ctrl, 0x07, tmp | 0x10);
|
||||
nv_wri2cr(mast, port->ctrl, 0x07, tmp);
|
||||
nv_wri2cr(mast, port->addr, 0x43, 0x05);
|
||||
mdelay(5);
|
||||
|
||||
while (cnt--) {
|
||||
if ( (msg->flags & I2C_M_RD) && msg->addr == 0x50) {
|
||||
nv_wri2cr(mast, port->addr, 0x40, msg->addr << 1);
|
||||
nv_wri2cr(mast, port->addr, 0x41, seg);
|
||||
nv_wri2cr(mast, port->addr, 0x42, off);
|
||||
nv_wri2cr(mast, port->addr, 0x44, msg->len);
|
||||
nv_wri2cr(mast, port->addr, 0x45, 0x00);
|
||||
nv_wri2cr(mast, port->addr, 0x43, 0x01);
|
||||
for (i = 0; i < msg->len; i++) {
|
||||
j = 0;
|
||||
while (nv_rdi2cr(mast, port->addr, 0x46) & 0x10) {
|
||||
mdelay(5);
|
||||
if (j++ == 32)
|
||||
goto done;
|
||||
}
|
||||
msg->buf[i] = nv_rdi2cr(mast, port->addr, 0x47);
|
||||
}
|
||||
} else
|
||||
if (!(msg->flags & I2C_M_RD)) {
|
||||
if (msg->addr == 0x50 && msg->len == 0x01) {
|
||||
off = msg->buf[0];
|
||||
} else
|
||||
if (msg->addr == 0x30 && msg->len == 0x01) {
|
||||
seg = msg->buf[0];
|
||||
} else
|
||||
goto done;
|
||||
} else {
|
||||
goto done;
|
||||
}
|
||||
msg++;
|
||||
}
|
||||
|
||||
ret = num;
|
||||
done:
|
||||
nv_wri2cr(mast, port->addr, 0x43, 0x00);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32
|
||||
anx9805_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm
|
||||
anx9805_i2c_algo = {
|
||||
.master_xfer = anx9805_xfer,
|
||||
.functionality = anx9805_func
|
||||
};
|
||||
|
||||
static const struct nouveau_i2c_func
|
||||
anx9805_i2c_func = {
|
||||
};
|
||||
|
||||
static int
|
||||
anx9805_ddc_port_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 index,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_i2c_port *mast = (void *)parent;
|
||||
struct anx9805_i2c_port *port;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_i2c_port_create(parent, engine, oclass, index,
|
||||
&anx9805_i2c_algo, &port);
|
||||
*pobject = nv_object(port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch ((oclass->handle & 0xff00) >> 8) {
|
||||
case 0x0d:
|
||||
port->addr = 0x3d;
|
||||
port->ctrl = 0x39;
|
||||
break;
|
||||
case 0x0e:
|
||||
port->addr = 0x3f;
|
||||
port->ctrl = 0x3b;
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
}
|
||||
|
||||
if (mast->adapter.algo == &i2c_bit_algo) {
|
||||
struct i2c_algo_bit_data *algo = mast->adapter.algo_data;
|
||||
algo->udelay = max(algo->udelay, 40);
|
||||
}
|
||||
|
||||
port->base.func = &anx9805_i2c_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_ofuncs
|
||||
anx9805_ddc_ofuncs = {
|
||||
.ctor = anx9805_ddc_port_ctor,
|
||||
.dtor = _nouveau_i2c_port_dtor,
|
||||
.init = _nouveau_i2c_port_init,
|
||||
.fini = _nouveau_i2c_port_fini,
|
||||
};
|
||||
|
||||
struct nouveau_oclass
|
||||
nouveau_anx9805_sclass[] = {
|
||||
{ .handle = NV_I2C_TYPE_EXTDDC(0x0d), .ofuncs = &anx9805_ddc_ofuncs },
|
||||
{ .handle = NV_I2C_TYPE_EXTAUX(0x0d), .ofuncs = &anx9805_aux_ofuncs },
|
||||
{ .handle = NV_I2C_TYPE_EXTDDC(0x0e), .ofuncs = &anx9805_ddc_ofuncs },
|
||||
{ .handle = NV_I2C_TYPE_EXTAUX(0x0e), .ofuncs = &anx9805_aux_ofuncs },
|
||||
{}
|
||||
};
|
@ -24,151 +24,40 @@
|
||||
|
||||
#include <subdev/i2c.h>
|
||||
|
||||
/******************************************************************************
|
||||
* aux channel util functions
|
||||
*****************************************************************************/
|
||||
#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
|
||||
#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
|
||||
|
||||
static void
|
||||
auxch_fini(struct nouveau_i2c *aux, int ch)
|
||||
int
|
||||
nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
|
||||
{
|
||||
nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000);
|
||||
}
|
||||
|
||||
static int
|
||||
auxch_init(struct nouveau_i2c *aux, int ch)
|
||||
{
|
||||
const u32 unksel = 1; /* nfi which to use, or if it matters.. */
|
||||
const u32 ureq = unksel ? 0x00100000 : 0x00200000;
|
||||
const u32 urep = unksel ? 0x01000000 : 0x02000000;
|
||||
u32 ctrl, timeout;
|
||||
|
||||
/* wait up to 1ms for any previous transaction to be done... */
|
||||
timeout = 1000;
|
||||
do {
|
||||
ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
|
||||
udelay(1);
|
||||
if (!timeout--) {
|
||||
AUX_ERR("begin idle timeout 0x%08x\n", ctrl);
|
||||
return -EBUSY;
|
||||
}
|
||||
} while (ctrl & 0x03010000);
|
||||
|
||||
/* set some magic, and wait up to 1ms for it to appear */
|
||||
nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq);
|
||||
timeout = 1000;
|
||||
do {
|
||||
ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
|
||||
udelay(1);
|
||||
if (!timeout--) {
|
||||
AUX_ERR("magic wait 0x%08x\n", ctrl);
|
||||
auxch_fini(aux, ch);
|
||||
return -EBUSY;
|
||||
}
|
||||
} while ((ctrl & 0x03000000) != urep);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
auxch_tx(struct nouveau_i2c *aux, int ch, u8 type, u32 addr, u8 *data, u8 size)
|
||||
{
|
||||
u32 ctrl, stat, timeout, retries;
|
||||
u32 xbuf[4] = {};
|
||||
int ret, i;
|
||||
|
||||
AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
|
||||
|
||||
ret = auxch_init(aux, ch);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
stat = nv_rd32(aux, 0x00e4e8 + (ch * 0x50));
|
||||
if (!(stat & 0x10000000)) {
|
||||
AUX_DBG("sink not detected\n");
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
if (port->func->aux) {
|
||||
if (port->func->acquire)
|
||||
port->func->acquire(port);
|
||||
return port->func->aux(port, 9, addr, data, size);
|
||||
}
|
||||
|
||||
if (!(type & 1)) {
|
||||
memcpy(xbuf, data, size);
|
||||
for (i = 0; i < 16; i += 4) {
|
||||
AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
|
||||
nv_wr32(aux, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]);
|
||||
}
|
||||
}
|
||||
|
||||
ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
|
||||
ctrl &= ~0x0001f0ff;
|
||||
ctrl |= type << 12;
|
||||
ctrl |= size - 1;
|
||||
nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr);
|
||||
|
||||
/* retry transaction a number of times on failure... */
|
||||
ret = -EREMOTEIO;
|
||||
for (retries = 0; retries < 32; retries++) {
|
||||
/* reset, and delay a while if this is a retry */
|
||||
nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
|
||||
nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl);
|
||||
if (retries)
|
||||
udelay(400);
|
||||
|
||||
/* transaction request, wait up to 1ms for it to complete */
|
||||
nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl);
|
||||
|
||||
timeout = 1000;
|
||||
do {
|
||||
ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
|
||||
udelay(1);
|
||||
if (!timeout--) {
|
||||
AUX_ERR("tx req timeout 0x%08x\n", ctrl);
|
||||
goto out;
|
||||
}
|
||||
} while (ctrl & 0x00010000);
|
||||
|
||||
/* read status, and check if transaction completed ok */
|
||||
stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0);
|
||||
if (!(stat & 0x000f0f00)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
|
||||
}
|
||||
|
||||
if (type & 1) {
|
||||
for (i = 0; i < 16; i += 4) {
|
||||
xbuf[i / 4] = nv_rd32(aux, 0x00e4d0 + (ch * 0x50) + i);
|
||||
AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
|
||||
}
|
||||
memcpy(data, xbuf, size);
|
||||
}
|
||||
|
||||
out:
|
||||
auxch_fini(aux, ch);
|
||||
return ret;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int
|
||||
nv_rdaux(struct nouveau_i2c_port *auxch, u32 addr, u8 *data, u8 size)
|
||||
nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
|
||||
{
|
||||
return auxch_tx(auxch->i2c, auxch->drive, 9, addr, data, size);
|
||||
}
|
||||
|
||||
int
|
||||
nv_wraux(struct nouveau_i2c_port *auxch, u32 addr, u8 *data, u8 size)
|
||||
{
|
||||
return auxch_tx(auxch->i2c, auxch->drive, 8, addr, data, size);
|
||||
if (port->func->aux) {
|
||||
if (port->func->acquire)
|
||||
port->func->acquire(port);
|
||||
return port->func->aux(port, 8, addr, data, size);
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int
|
||||
aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct nouveau_i2c_port *auxch = (struct nouveau_i2c_port *)adap;
|
||||
struct nouveau_i2c_port *port = adap->algo_data;
|
||||
struct i2c_msg *msg = msgs;
|
||||
int ret, mcnt = num;
|
||||
|
||||
if (!port->func->aux)
|
||||
return -ENODEV;
|
||||
if ( port->func->acquire)
|
||||
port->func->acquire(port);
|
||||
|
||||
while (mcnt--) {
|
||||
u8 remaining = msg->len;
|
||||
u8 *ptr = msg->buf;
|
||||
@ -185,8 +74,7 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
if (mcnt || remaining > 16)
|
||||
cmd |= 4; /* MOT */
|
||||
|
||||
ret = auxch_tx(auxch->i2c, auxch->drive, cmd,
|
||||
msg->addr, ptr, cnt);
|
||||
ret = port->func->aux(port, cmd, msg->addr, ptr, cnt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
* Copyright 2013 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"),
|
||||
@ -22,64 +22,136 @@
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include "core/option.h"
|
||||
#include <core/option.h>
|
||||
|
||||
#include "subdev/i2c.h"
|
||||
#include "subdev/vga.h"
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bios/dcb.h>
|
||||
#include <subdev/bios/i2c.h>
|
||||
#include <subdev/i2c.h>
|
||||
#include <subdev/vga.h>
|
||||
|
||||
int
|
||||
nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg)
|
||||
/******************************************************************************
|
||||
* interface to linux i2c bit-banging algorithm
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT
|
||||
#define CSTMSEL true
|
||||
#else
|
||||
#define CSTMSEL false
|
||||
#endif
|
||||
|
||||
static int
|
||||
nouveau_i2c_pre_xfer(struct i2c_adapter *adap)
|
||||
{
|
||||
u8 val;
|
||||
struct i2c_msg msgs[] = {
|
||||
{ .addr = addr, .flags = 0, .len = 1, .buf = ® },
|
||||
{ .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = &val },
|
||||
};
|
||||
|
||||
int ret = i2c_transfer(&port->adapter, msgs, 2);
|
||||
if (ret != 2)
|
||||
return -EIO;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int
|
||||
nv_wri2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg, u8 val)
|
||||
{
|
||||
struct i2c_msg msgs[] = {
|
||||
{ .addr = addr, .flags = 0, .len = 1, .buf = ® },
|
||||
{ .addr = addr, .flags = 0, .len = 1, .buf = &val },
|
||||
};
|
||||
|
||||
int ret = i2c_transfer(&port->adapter, msgs, 2);
|
||||
if (ret != 2)
|
||||
return -EIO;
|
||||
|
||||
struct i2c_algo_bit_data *bit = adap->algo_data;
|
||||
struct nouveau_i2c_port *port = bit->data;
|
||||
if (port->func->acquire)
|
||||
port->func->acquire(port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
nv_probe_i2c(struct nouveau_i2c_port *port, u8 addr)
|
||||
static void
|
||||
nouveau_i2c_setscl(void *data, int state)
|
||||
{
|
||||
u8 buf[] = { 0 };
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = addr,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = buf,
|
||||
},
|
||||
{
|
||||
.addr = addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = 1,
|
||||
.buf = buf,
|
||||
}
|
||||
};
|
||||
|
||||
return i2c_transfer(&port->adapter, msgs, 2) == 2;
|
||||
struct nouveau_i2c_port *port = data;
|
||||
port->func->drive_scl(port, state);
|
||||
}
|
||||
|
||||
static void
|
||||
nouveau_i2c_setsda(void *data, int state)
|
||||
{
|
||||
struct nouveau_i2c_port *port = data;
|
||||
port->func->drive_sda(port, state);
|
||||
}
|
||||
|
||||
static int
|
||||
nouveau_i2c_getscl(void *data)
|
||||
{
|
||||
struct nouveau_i2c_port *port = data;
|
||||
return port->func->sense_scl(port);
|
||||
}
|
||||
|
||||
static int
|
||||
nouveau_i2c_getsda(void *data)
|
||||
{
|
||||
struct nouveau_i2c_port *port = data;
|
||||
return port->func->sense_sda(port);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* base i2c "port" class implementation
|
||||
*****************************************************************************/
|
||||
|
||||
void
|
||||
_nouveau_i2c_port_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_i2c_port *port = (void *)object;
|
||||
i2c_del_adapter(&port->adapter);
|
||||
nouveau_object_destroy(&port->base);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_i2c_port_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, u8 index,
|
||||
const struct i2c_algorithm *algo,
|
||||
int size, void **pobject)
|
||||
{
|
||||
struct nouveau_device *device = nv_device(parent);
|
||||
struct nouveau_i2c *i2c = (void *)engine;
|
||||
struct nouveau_i2c_port *port;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_object_create_(parent, engine, oclass, 0, size, pobject);
|
||||
port = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
snprintf(port->adapter.name, sizeof(port->adapter.name),
|
||||
"nouveau-%s-%d", device->name, index);
|
||||
port->adapter.owner = THIS_MODULE;
|
||||
port->adapter.dev.parent = &device->pdev->dev;
|
||||
port->index = index;
|
||||
i2c_set_adapdata(&port->adapter, i2c);
|
||||
|
||||
if ( algo == &nouveau_i2c_bit_algo &&
|
||||
!nouveau_boolopt(device->cfgopt, "NvI2C", CSTMSEL)) {
|
||||
struct i2c_algo_bit_data *bit;
|
||||
|
||||
bit = kzalloc(sizeof(*bit), GFP_KERNEL);
|
||||
if (!bit)
|
||||
return -ENOMEM;
|
||||
|
||||
bit->udelay = 10;
|
||||
bit->timeout = usecs_to_jiffies(2200);
|
||||
bit->data = port;
|
||||
bit->pre_xfer = nouveau_i2c_pre_xfer;
|
||||
bit->setsda = nouveau_i2c_setsda;
|
||||
bit->setscl = nouveau_i2c_setscl;
|
||||
bit->getsda = nouveau_i2c_getsda;
|
||||
bit->getscl = nouveau_i2c_getscl;
|
||||
|
||||
port->adapter.algo_data = bit;
|
||||
ret = i2c_bit_add_bus(&port->adapter);
|
||||
} else {
|
||||
port->adapter.algo_data = port;
|
||||
port->adapter.algo = algo;
|
||||
ret = i2c_add_adapter(&port->adapter);
|
||||
}
|
||||
|
||||
/* drop port's i2c subdev refcount, i2c handles this itself */
|
||||
if (ret == 0) {
|
||||
list_add_tail(&port->head, &i2c->ports);
|
||||
atomic_dec(&engine->refcount);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* base i2c subdev class implementation
|
||||
*****************************************************************************/
|
||||
|
||||
static struct nouveau_i2c_port *
|
||||
nouveau_i2c_find(struct nouveau_i2c *i2c, u8 index)
|
||||
{
|
||||
@ -103,29 +175,23 @@ nouveau_i2c_find(struct nouveau_i2c *i2c, u8 index)
|
||||
|
||||
list_for_each_entry(port, &i2c->ports, head) {
|
||||
if (port->index == index)
|
||||
break;
|
||||
return port;
|
||||
}
|
||||
|
||||
if (&port->head == &i2c->ports)
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (nv_device(i2c)->card_type >= NV_50 && (port->dcb & 0x00000100)) {
|
||||
u32 reg = 0x00e500, val;
|
||||
if (port->type == 6) {
|
||||
reg += port->drive * 0x50;
|
||||
val = 0x2002;
|
||||
} else {
|
||||
reg += ((port->dcb & 0x1e00) >> 9) * 0x50;
|
||||
val = 0xe001;
|
||||
}
|
||||
static struct nouveau_i2c_port *
|
||||
nouveau_i2c_find_type(struct nouveau_i2c *i2c, u16 type)
|
||||
{
|
||||
struct nouveau_i2c_port *port;
|
||||
|
||||
/* nfi, but neither auxch or i2c work if it's 1 */
|
||||
nv_mask(i2c, reg + 0x0c, 0x00000001, 0x00000000);
|
||||
/* nfi, but switches auxch vs normal i2c */
|
||||
nv_mask(i2c, reg + 0x00, 0x0000f003, val);
|
||||
list_for_each_entry(port, &i2c->ports, head) {
|
||||
if (nv_hclass(port) == type)
|
||||
return port;
|
||||
}
|
||||
|
||||
return port;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -155,109 +221,86 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_i2c_drive_scl(void *data, int state)
|
||||
int
|
||||
_nouveau_i2c_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
struct nouveau_i2c_port *port = data;
|
||||
struct nouveau_i2c *i2c = (void *)object;
|
||||
struct nouveau_i2c_port *port;
|
||||
int ret;
|
||||
|
||||
if (port->type == DCB_I2C_NV04_BIT) {
|
||||
u8 val = nv_rdvgac(port->i2c, 0, port->drive);
|
||||
if (state) val |= 0x20;
|
||||
else val &= 0xdf;
|
||||
nv_wrvgac(port->i2c, 0, port->drive, val | 0x01);
|
||||
} else
|
||||
if (port->type == DCB_I2C_NV4E_BIT) {
|
||||
nv_mask(port->i2c, port->drive, 0x2f, state ? 0x21 : 0x01);
|
||||
} else
|
||||
if (port->type == DCB_I2C_NVIO_BIT) {
|
||||
if (state) port->state |= 0x01;
|
||||
else port->state &= 0xfe;
|
||||
nv_wr32(port->i2c, port->drive, 4 | port->state);
|
||||
list_for_each_entry(port, &i2c->ports, head) {
|
||||
ret = nv_ofuncs(port)->fini(nv_object(port), suspend);
|
||||
if (ret && suspend)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_i2c_drive_sda(void *data, int state)
|
||||
{
|
||||
struct nouveau_i2c_port *port = data;
|
||||
|
||||
if (port->type == DCB_I2C_NV04_BIT) {
|
||||
u8 val = nv_rdvgac(port->i2c, 0, port->drive);
|
||||
if (state) val |= 0x10;
|
||||
else val &= 0xef;
|
||||
nv_wrvgac(port->i2c, 0, port->drive, val | 0x01);
|
||||
} else
|
||||
if (port->type == DCB_I2C_NV4E_BIT) {
|
||||
nv_mask(port->i2c, port->drive, 0x1f, state ? 0x11 : 0x01);
|
||||
} else
|
||||
if (port->type == DCB_I2C_NVIO_BIT) {
|
||||
if (state) port->state |= 0x02;
|
||||
else port->state &= 0xfd;
|
||||
nv_wr32(port->i2c, port->drive, 4 | port->state);
|
||||
return nouveau_subdev_fini(&i2c->base, suspend);
|
||||
fail:
|
||||
list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
|
||||
nv_ofuncs(port)->init(nv_object(port));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_i2c_sense_scl(void *data)
|
||||
_nouveau_i2c_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_i2c_port *port = data;
|
||||
struct nouveau_device *device = nv_device(port->i2c);
|
||||
struct nouveau_i2c *i2c = (void *)object;
|
||||
struct nouveau_i2c_port *port;
|
||||
int ret;
|
||||
|
||||
if (port->type == DCB_I2C_NV04_BIT) {
|
||||
return !!(nv_rdvgac(port->i2c, 0, port->sense) & 0x04);
|
||||
} else
|
||||
if (port->type == DCB_I2C_NV4E_BIT) {
|
||||
return !!(nv_rd32(port->i2c, port->sense) & 0x00040000);
|
||||
} else
|
||||
if (port->type == DCB_I2C_NVIO_BIT) {
|
||||
if (device->card_type < NV_D0)
|
||||
return !!(nv_rd32(port->i2c, port->sense) & 0x01);
|
||||
else
|
||||
return !!(nv_rd32(port->i2c, port->sense) & 0x10);
|
||||
ret = nouveau_subdev_init(&i2c->base);
|
||||
if (ret == 0) {
|
||||
list_for_each_entry(port, &i2c->ports, head) {
|
||||
ret = nv_ofuncs(port)->init(nv_object(port));
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_i2c_sense_sda(void *data)
|
||||
{
|
||||
struct nouveau_i2c_port *port = data;
|
||||
struct nouveau_device *device = nv_device(port->i2c);
|
||||
|
||||
if (port->type == DCB_I2C_NV04_BIT) {
|
||||
return !!(nv_rdvgac(port->i2c, 0, port->sense) & 0x08);
|
||||
} else
|
||||
if (port->type == DCB_I2C_NV4E_BIT) {
|
||||
return !!(nv_rd32(port->i2c, port->sense) & 0x00080000);
|
||||
} else
|
||||
if (port->type == DCB_I2C_NVIO_BIT) {
|
||||
if (device->card_type < NV_D0)
|
||||
return !!(nv_rd32(port->i2c, port->sense) & 0x02);
|
||||
else
|
||||
return !!(nv_rd32(port->i2c, port->sense) & 0x20);
|
||||
return ret;
|
||||
fail:
|
||||
list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
|
||||
nv_ofuncs(port)->fini(nv_object(port), false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const u32 nv50_i2c_port[] = {
|
||||
0x00e138, 0x00e150, 0x00e168, 0x00e180,
|
||||
0x00e254, 0x00e274, 0x00e764, 0x00e780,
|
||||
0x00e79c, 0x00e7b8
|
||||
void
|
||||
_nouveau_i2c_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_i2c *i2c = (void *)object;
|
||||
struct nouveau_i2c_port *port, *temp;
|
||||
|
||||
list_for_each_entry_safe(port, temp, &i2c->ports, head) {
|
||||
nouveau_object_ref(NULL, (struct nouveau_object **)&port);
|
||||
}
|
||||
|
||||
nouveau_subdev_destroy(&i2c->base);
|
||||
}
|
||||
|
||||
static struct nouveau_oclass *
|
||||
nouveau_i2c_extdev_sclass[] = {
|
||||
nouveau_anx9805_sclass,
|
||||
};
|
||||
|
||||
static int
|
||||
nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
int
|
||||
nouveau_i2c_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass,
|
||||
struct nouveau_oclass *sclass,
|
||||
int length, void **pobject)
|
||||
{
|
||||
struct nouveau_device *device = nv_device(parent);
|
||||
struct nouveau_bios *bios = nouveau_bios(parent);
|
||||
struct nouveau_i2c_port *port;
|
||||
struct nouveau_i2c *i2c;
|
||||
struct nouveau_object *object;
|
||||
struct dcb_i2c_entry info;
|
||||
int ret, i = -1;
|
||||
int ret, i, j, index = -1;
|
||||
struct dcb_output outp;
|
||||
u8 ver, hdr;
|
||||
u32 data;
|
||||
|
||||
ret = nouveau_subdev_create(parent, engine, oclass, 0,
|
||||
"I2C", "i2c", &i2c);
|
||||
@ -266,142 +309,60 @@ nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
return ret;
|
||||
|
||||
i2c->find = nouveau_i2c_find;
|
||||
i2c->find_type = nouveau_i2c_find_type;
|
||||
i2c->identify = nouveau_i2c_identify;
|
||||
INIT_LIST_HEAD(&i2c->ports);
|
||||
|
||||
while (!dcb_i2c_parse(bios, ++i, &info)) {
|
||||
while (!dcb_i2c_parse(bios, ++index, &info)) {
|
||||
if (info.type == DCB_I2C_UNUSED)
|
||||
continue;
|
||||
|
||||
port = kzalloc(sizeof(*port), GFP_KERNEL);
|
||||
if (!port) {
|
||||
nv_error(i2c, "failed port memory alloc at %d\n", i);
|
||||
break;
|
||||
}
|
||||
|
||||
port->type = info.type;
|
||||
switch (port->type) {
|
||||
case DCB_I2C_NV04_BIT:
|
||||
port->drive = info.drive;
|
||||
port->sense = info.sense;
|
||||
break;
|
||||
case DCB_I2C_NV4E_BIT:
|
||||
port->drive = 0x600800 + info.drive;
|
||||
port->sense = port->drive;
|
||||
break;
|
||||
case DCB_I2C_NVIO_BIT:
|
||||
port->drive = info.drive & 0x0f;
|
||||
if (device->card_type < NV_D0) {
|
||||
if (port->drive >= ARRAY_SIZE(nv50_i2c_port))
|
||||
break;
|
||||
port->drive = nv50_i2c_port[port->drive];
|
||||
port->sense = port->drive;
|
||||
} else {
|
||||
port->drive = 0x00d014 + (port->drive * 0x20);
|
||||
port->sense = port->drive;
|
||||
oclass = sclass;
|
||||
do {
|
||||
ret = -EINVAL;
|
||||
if (oclass->handle == info.type) {
|
||||
ret = nouveau_object_ctor(*pobject, *pobject,
|
||||
oclass, &info,
|
||||
index, &object);
|
||||
}
|
||||
} while (ret && (++oclass)->handle);
|
||||
}
|
||||
|
||||
/* in addition to the busses specified in the i2c table, there
|
||||
* may be ddc/aux channels hiding behind external tmds/dp/etc
|
||||
* transmitters.
|
||||
*/
|
||||
index = ((index + 0x0f) / 0x10) * 0x10;
|
||||
i = -1;
|
||||
while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &outp))) {
|
||||
if (!outp.location || !outp.extdev)
|
||||
continue;
|
||||
|
||||
switch (outp.type) {
|
||||
case DCB_OUTPUT_TMDS:
|
||||
info.type = NV_I2C_TYPE_EXTDDC(outp.extdev);
|
||||
break;
|
||||
case DCB_I2C_NVIO_AUX:
|
||||
port->drive = info.drive & 0x0f;
|
||||
port->sense = port->drive;
|
||||
port->adapter.algo = &nouveau_i2c_aux_algo;
|
||||
case DCB_OUTPUT_DP:
|
||||
info.type = NV_I2C_TYPE_EXTAUX(outp.extdev);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!port->adapter.algo && !port->drive) {
|
||||
nv_error(i2c, "I2C%d: type %d index %x/%x unknown\n",
|
||||
i, port->type, port->drive, port->sense);
|
||||
kfree(port);
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(port->adapter.name, sizeof(port->adapter.name),
|
||||
"nouveau-%s-%d", device->name, i);
|
||||
port->adapter.owner = THIS_MODULE;
|
||||
port->adapter.dev.parent = &device->pdev->dev;
|
||||
port->i2c = i2c;
|
||||
port->index = i;
|
||||
port->dcb = info.data;
|
||||
i2c_set_adapdata(&port->adapter, i2c);
|
||||
|
||||
if (port->adapter.algo != &nouveau_i2c_aux_algo) {
|
||||
nouveau_i2c_drive_scl(port, 0);
|
||||
nouveau_i2c_drive_sda(port, 1);
|
||||
nouveau_i2c_drive_scl(port, 1);
|
||||
|
||||
#ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT
|
||||
if (nouveau_boolopt(device->cfgopt, "NvI2C", true)) {
|
||||
#else
|
||||
if (nouveau_boolopt(device->cfgopt, "NvI2C", false)) {
|
||||
#endif
|
||||
port->adapter.algo = &nouveau_i2c_bit_algo;
|
||||
ret = i2c_add_adapter(&port->adapter);
|
||||
} else {
|
||||
port->adapter.algo_data = &port->bit;
|
||||
port->bit.udelay = 10;
|
||||
port->bit.timeout = usecs_to_jiffies(2200);
|
||||
port->bit.data = port;
|
||||
port->bit.setsda = nouveau_i2c_drive_sda;
|
||||
port->bit.setscl = nouveau_i2c_drive_scl;
|
||||
port->bit.getsda = nouveau_i2c_sense_sda;
|
||||
port->bit.getscl = nouveau_i2c_sense_scl;
|
||||
ret = i2c_bit_add_bus(&port->adapter);
|
||||
}
|
||||
} else {
|
||||
port->adapter.algo = &nouveau_i2c_aux_algo;
|
||||
ret = i2c_add_adapter(&port->adapter);
|
||||
ret = -ENODEV;
|
||||
j = -1;
|
||||
while (ret && ++j < ARRAY_SIZE(nouveau_i2c_extdev_sclass)) {
|
||||
parent = nv_object(i2c->find(i2c, outp.i2c_index));
|
||||
oclass = nouveau_i2c_extdev_sclass[j];
|
||||
do {
|
||||
if (oclass->handle != info.type)
|
||||
continue;
|
||||
ret = nouveau_object_ctor(parent, *pobject,
|
||||
oclass, NULL,
|
||||
index++, &object);
|
||||
} while (ret && (++oclass)->handle);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
nv_error(i2c, "I2C%d: failed register: %d\n", i, ret);
|
||||
kfree(port);
|
||||
continue;
|
||||
}
|
||||
|
||||
list_add_tail(&port->head, &i2c->ports);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nouveau_i2c_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_i2c *i2c = (void *)object;
|
||||
struct nouveau_i2c_port *port, *temp;
|
||||
|
||||
list_for_each_entry_safe(port, temp, &i2c->ports, head) {
|
||||
i2c_del_adapter(&port->adapter);
|
||||
list_del(&port->head);
|
||||
kfree(port);
|
||||
}
|
||||
|
||||
nouveau_subdev_destroy(&i2c->base);
|
||||
}
|
||||
|
||||
static int
|
||||
nouveau_i2c_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_i2c *i2c = (void *)object;
|
||||
return nouveau_subdev_init(&i2c->base);
|
||||
}
|
||||
|
||||
static int
|
||||
nouveau_i2c_fini(struct nouveau_object *object, bool suspend)
|
||||
{
|
||||
struct nouveau_i2c *i2c = (void *)object;
|
||||
return nouveau_subdev_fini(&i2c->base, suspend);
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nouveau_i2c_oclass = {
|
||||
.handle = NV_SUBDEV(I2C, 0x00),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nouveau_i2c_ctor,
|
||||
.dtor = nouveau_i2c_dtor,
|
||||
.init = nouveau_i2c_init,
|
||||
.fini = nouveau_i2c_fini,
|
||||
},
|
||||
};
|
||||
|
@ -32,25 +32,25 @@
|
||||
static inline void
|
||||
i2c_drive_scl(struct nouveau_i2c_port *port, int state)
|
||||
{
|
||||
nouveau_i2c_drive_scl(port, state);
|
||||
port->func->drive_scl(port, state);
|
||||
}
|
||||
|
||||
static inline void
|
||||
i2c_drive_sda(struct nouveau_i2c_port *port, int state)
|
||||
{
|
||||
nouveau_i2c_drive_sda(port, state);
|
||||
port->func->drive_sda(port, state);
|
||||
}
|
||||
|
||||
static inline int
|
||||
i2c_sense_scl(struct nouveau_i2c_port *port)
|
||||
{
|
||||
return nouveau_i2c_sense_scl(port);
|
||||
return port->func->sense_scl(port);
|
||||
}
|
||||
|
||||
static inline int
|
||||
i2c_sense_sda(struct nouveau_i2c_port *port)
|
||||
{
|
||||
return nouveau_i2c_sense_sda(port);
|
||||
return port->func->sense_sda(port);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -77,9 +77,8 @@ i2c_start(struct nouveau_i2c_port *port)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
port->state = i2c_sense_scl(port);
|
||||
port->state |= i2c_sense_sda(port) << 1;
|
||||
if (port->state != 3) {
|
||||
if (!i2c_sense_scl(port) ||
|
||||
!i2c_sense_sda(port)) {
|
||||
i2c_drive_scl(port, 0);
|
||||
i2c_drive_sda(port, 1);
|
||||
if (!i2c_raise_scl(port))
|
||||
@ -184,10 +183,13 @@ i2c_addr(struct nouveau_i2c_port *port, struct i2c_msg *msg)
|
||||
static int
|
||||
i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct nouveau_i2c_port *port = (struct nouveau_i2c_port *)adap;
|
||||
struct nouveau_i2c_port *port = adap->algo_data;
|
||||
struct i2c_msg *msg = msgs;
|
||||
int ret = 0, mcnt = num;
|
||||
|
||||
if (port->func->acquire)
|
||||
port->func->acquire(port);
|
||||
|
||||
while (!ret && mcnt--) {
|
||||
u8 remaining = msg->len;
|
||||
u8 *ptr = msg->buf;
|
||||
|
143
drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c
Normal file
143
drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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 <subdev/i2c.h>
|
||||
#include <subdev/vga.h>
|
||||
|
||||
struct nv04_i2c_priv {
|
||||
struct nouveau_i2c base;
|
||||
};
|
||||
|
||||
struct nv04_i2c_port {
|
||||
struct nouveau_i2c_port base;
|
||||
u8 drive;
|
||||
u8 sense;
|
||||
};
|
||||
|
||||
static void
|
||||
nv04_i2c_drive_scl(struct nouveau_i2c_port *base, int state)
|
||||
{
|
||||
struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine;
|
||||
struct nv04_i2c_port *port = (void *)base;
|
||||
u8 val = nv_rdvgac(priv, 0, port->drive);
|
||||
if (state) val |= 0x20;
|
||||
else val &= 0xdf;
|
||||
nv_wrvgac(priv, 0, port->drive, val | 0x01);
|
||||
}
|
||||
|
||||
static void
|
||||
nv04_i2c_drive_sda(struct nouveau_i2c_port *base, int state)
|
||||
{
|
||||
struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine;
|
||||
struct nv04_i2c_port *port = (void *)base;
|
||||
u8 val = nv_rdvgac(priv, 0, port->drive);
|
||||
if (state) val |= 0x10;
|
||||
else val &= 0xef;
|
||||
nv_wrvgac(priv, 0, port->drive, val | 0x01);
|
||||
}
|
||||
|
||||
static int
|
||||
nv04_i2c_sense_scl(struct nouveau_i2c_port *base)
|
||||
{
|
||||
struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine;
|
||||
struct nv04_i2c_port *port = (void *)base;
|
||||
return !!(nv_rdvgac(priv, 0, port->sense) & 0x04);
|
||||
}
|
||||
|
||||
static int
|
||||
nv04_i2c_sense_sda(struct nouveau_i2c_port *base)
|
||||
{
|
||||
struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine;
|
||||
struct nv04_i2c_port *port = (void *)base;
|
||||
return !!(nv_rdvgac(priv, 0, port->sense) & 0x08);
|
||||
}
|
||||
|
||||
static const struct nouveau_i2c_func
|
||||
nv04_i2c_func = {
|
||||
.drive_scl = nv04_i2c_drive_scl,
|
||||
.drive_sda = nv04_i2c_drive_sda,
|
||||
.sense_scl = nv04_i2c_sense_scl,
|
||||
.sense_sda = nv04_i2c_sense_sda,
|
||||
};
|
||||
|
||||
static int
|
||||
nv04_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 index,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct dcb_i2c_entry *info = data;
|
||||
struct nv04_i2c_port *port;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_i2c_port_create(parent, engine, oclass, index,
|
||||
&nouveau_i2c_bit_algo, &port);
|
||||
*pobject = nv_object(port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
port->base.func = &nv04_i2c_func;
|
||||
port->drive = info->drive;
|
||||
port->sense = info->sense;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv04_i2c_sclass[] = {
|
||||
{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV04_BIT),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv04_i2c_port_ctor,
|
||||
.dtor = _nouveau_i2c_port_dtor,
|
||||
.init = _nouveau_i2c_port_init,
|
||||
.fini = _nouveau_i2c_port_fini,
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static int
|
||||
nv04_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv04_i2c_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_i2c_create(parent, engine, oclass, nv04_i2c_sclass, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv04_i2c_oclass = {
|
||||
.handle = NV_SUBDEV(I2C, 0x04),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv04_i2c_ctor,
|
||||
.dtor = _nouveau_i2c_dtor,
|
||||
.init = _nouveau_i2c_init,
|
||||
.fini = _nouveau_i2c_fini,
|
||||
},
|
||||
};
|
135
drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c
Normal file
135
drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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 <subdev/i2c.h>
|
||||
#include <subdev/vga.h>
|
||||
|
||||
struct nv4e_i2c_priv {
|
||||
struct nouveau_i2c base;
|
||||
};
|
||||
|
||||
struct nv4e_i2c_port {
|
||||
struct nouveau_i2c_port base;
|
||||
u32 addr;
|
||||
};
|
||||
|
||||
static void
|
||||
nv4e_i2c_drive_scl(struct nouveau_i2c_port *base, int state)
|
||||
{
|
||||
struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine;
|
||||
struct nv4e_i2c_port *port = (void *)base;
|
||||
nv_mask(priv, port->addr, 0x2f, state ? 0x21 : 0x01);
|
||||
}
|
||||
|
||||
static void
|
||||
nv4e_i2c_drive_sda(struct nouveau_i2c_port *base, int state)
|
||||
{
|
||||
struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine;
|
||||
struct nv4e_i2c_port *port = (void *)base;
|
||||
nv_mask(priv, port->addr, 0x1f, state ? 0x11 : 0x01);
|
||||
}
|
||||
|
||||
static int
|
||||
nv4e_i2c_sense_scl(struct nouveau_i2c_port *base)
|
||||
{
|
||||
struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine;
|
||||
struct nv4e_i2c_port *port = (void *)base;
|
||||
return !!(nv_rd32(priv, port->addr) & 0x00040000);
|
||||
}
|
||||
|
||||
static int
|
||||
nv4e_i2c_sense_sda(struct nouveau_i2c_port *base)
|
||||
{
|
||||
struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine;
|
||||
struct nv4e_i2c_port *port = (void *)base;
|
||||
return !!(nv_rd32(priv, port->addr) & 0x00080000);
|
||||
}
|
||||
|
||||
static const struct nouveau_i2c_func
|
||||
nv4e_i2c_func = {
|
||||
.drive_scl = nv4e_i2c_drive_scl,
|
||||
.drive_sda = nv4e_i2c_drive_sda,
|
||||
.sense_scl = nv4e_i2c_sense_scl,
|
||||
.sense_sda = nv4e_i2c_sense_sda,
|
||||
};
|
||||
|
||||
static int
|
||||
nv4e_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 index,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct dcb_i2c_entry *info = data;
|
||||
struct nv4e_i2c_port *port;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_i2c_port_create(parent, engine, oclass, index,
|
||||
&nouveau_i2c_bit_algo, &port);
|
||||
*pobject = nv_object(port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
port->base.func = &nv4e_i2c_func;
|
||||
port->addr = 0x600800 + info->drive;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv4e_i2c_sclass[] = {
|
||||
{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV4E_BIT),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv4e_i2c_port_ctor,
|
||||
.dtor = _nouveau_i2c_port_dtor,
|
||||
.init = _nouveau_i2c_port_init,
|
||||
.fini = _nouveau_i2c_port_fini,
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static int
|
||||
nv4e_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv4e_i2c_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_i2c_create(parent, engine, oclass, nv4e_i2c_sclass, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv4e_i2c_oclass = {
|
||||
.handle = NV_SUBDEV(I2C, 0x4e),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv4e_i2c_ctor,
|
||||
.dtor = _nouveau_i2c_dtor,
|
||||
.init = _nouveau_i2c_init,
|
||||
.fini = _nouveau_i2c_fini,
|
||||
},
|
||||
};
|
149
drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c
Normal file
149
drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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 "nv50.h"
|
||||
|
||||
void
|
||||
nv50_i2c_drive_scl(struct nouveau_i2c_port *base, int state)
|
||||
{
|
||||
struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
|
||||
struct nv50_i2c_port *port = (void *)base;
|
||||
if (state) port->state |= 0x01;
|
||||
else port->state &= 0xfe;
|
||||
nv_wr32(priv, port->addr, port->state);
|
||||
}
|
||||
|
||||
void
|
||||
nv50_i2c_drive_sda(struct nouveau_i2c_port *base, int state)
|
||||
{
|
||||
struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
|
||||
struct nv50_i2c_port *port = (void *)base;
|
||||
if (state) port->state |= 0x02;
|
||||
else port->state &= 0xfd;
|
||||
nv_wr32(priv, port->addr, port->state);
|
||||
}
|
||||
|
||||
int
|
||||
nv50_i2c_sense_scl(struct nouveau_i2c_port *base)
|
||||
{
|
||||
struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
|
||||
struct nv50_i2c_port *port = (void *)base;
|
||||
return !!(nv_rd32(priv, port->addr) & 0x00000001);
|
||||
}
|
||||
|
||||
int
|
||||
nv50_i2c_sense_sda(struct nouveau_i2c_port *base)
|
||||
{
|
||||
struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
|
||||
struct nv50_i2c_port *port = (void *)base;
|
||||
return !!(nv_rd32(priv, port->addr) & 0x00000002);
|
||||
}
|
||||
|
||||
static const struct nouveau_i2c_func
|
||||
nv50_i2c_func = {
|
||||
.drive_scl = nv50_i2c_drive_scl,
|
||||
.drive_sda = nv50_i2c_drive_sda,
|
||||
.sense_scl = nv50_i2c_sense_scl,
|
||||
.sense_sda = nv50_i2c_sense_sda,
|
||||
};
|
||||
|
||||
const u32 nv50_i2c_addr[] = {
|
||||
0x00e138, 0x00e150, 0x00e168, 0x00e180,
|
||||
0x00e254, 0x00e274, 0x00e764, 0x00e780,
|
||||
0x00e79c, 0x00e7b8
|
||||
};
|
||||
const int nv50_i2c_addr_nr = ARRAY_SIZE(nv50_i2c_addr);
|
||||
|
||||
static int
|
||||
nv50_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 index,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct dcb_i2c_entry *info = data;
|
||||
struct nv50_i2c_port *port;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_i2c_port_create(parent, engine, oclass, index,
|
||||
&nouveau_i2c_bit_algo, &port);
|
||||
*pobject = nv_object(port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (info->drive >= nv50_i2c_addr_nr)
|
||||
return -EINVAL;
|
||||
|
||||
port->base.func = &nv50_i2c_func;
|
||||
port->state = 0x00000007;
|
||||
port->addr = nv50_i2c_addr[info->drive];
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nv50_i2c_port_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nv50_i2c_priv *priv = (void *)object->engine;
|
||||
struct nv50_i2c_port *port = (void *)object;
|
||||
nv_wr32(priv, port->addr, port->state);
|
||||
return nouveau_i2c_port_init(&port->base);
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv50_i2c_sclass[] = {
|
||||
{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv50_i2c_port_ctor,
|
||||
.dtor = _nouveau_i2c_port_dtor,
|
||||
.init = nv50_i2c_port_init,
|
||||
.fini = _nouveau_i2c_port_fini,
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static int
|
||||
nv50_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv50_i2c_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_i2c_create(parent, engine, oclass, nv50_i2c_sclass, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv50_i2c_oclass = {
|
||||
.handle = NV_SUBDEV(I2C, 0x50),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv50_i2c_ctor,
|
||||
.dtor = _nouveau_i2c_dtor,
|
||||
.init = _nouveau_i2c_init,
|
||||
.fini = _nouveau_i2c_fini,
|
||||
},
|
||||
};
|
32
drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h
Normal file
32
drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef __NV50_I2C_H__
|
||||
#define __NV50_I2C_H__
|
||||
|
||||
#include <subdev/i2c.h>
|
||||
|
||||
struct nv50_i2c_priv {
|
||||
struct nouveau_i2c base;
|
||||
};
|
||||
|
||||
struct nv50_i2c_port {
|
||||
struct nouveau_i2c_port base;
|
||||
u32 addr;
|
||||
u32 ctrl;
|
||||
u32 data;
|
||||
u32 state;
|
||||
};
|
||||
|
||||
extern const u32 nv50_i2c_addr[];
|
||||
extern const int nv50_i2c_addr_nr;
|
||||
int nv50_i2c_port_init(struct nouveau_object *);
|
||||
int nv50_i2c_sense_scl(struct nouveau_i2c_port *);
|
||||
int nv50_i2c_sense_sda(struct nouveau_i2c_port *);
|
||||
void nv50_i2c_drive_scl(struct nouveau_i2c_port *, int state);
|
||||
void nv50_i2c_drive_sda(struct nouveau_i2c_port *, int state);
|
||||
|
||||
int nv94_aux_port_ctor(struct nouveau_object *, struct nouveau_object *,
|
||||
struct nouveau_oclass *, void *, u32,
|
||||
struct nouveau_object **);
|
||||
void nv94_i2c_acquire(struct nouveau_i2c_port *);
|
||||
void nv94_i2c_release(struct nouveau_i2c_port *);
|
||||
|
||||
#endif
|
285
drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
Normal file
285
drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
Normal file
@ -0,0 +1,285 @@
|
||||
/*
|
||||
* 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 "nv50.h"
|
||||
|
||||
#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
|
||||
#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
|
||||
|
||||
static void
|
||||
auxch_fini(struct nouveau_i2c *aux, int ch)
|
||||
{
|
||||
nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000);
|
||||
}
|
||||
|
||||
static int
|
||||
auxch_init(struct nouveau_i2c *aux, int ch)
|
||||
{
|
||||
const u32 unksel = 1; /* nfi which to use, or if it matters.. */
|
||||
const u32 ureq = unksel ? 0x00100000 : 0x00200000;
|
||||
const u32 urep = unksel ? 0x01000000 : 0x02000000;
|
||||
u32 ctrl, timeout;
|
||||
|
||||
/* wait up to 1ms for any previous transaction to be done... */
|
||||
timeout = 1000;
|
||||
do {
|
||||
ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
|
||||
udelay(1);
|
||||
if (!timeout--) {
|
||||
AUX_ERR("begin idle timeout 0x%08x\n", ctrl);
|
||||
return -EBUSY;
|
||||
}
|
||||
} while (ctrl & 0x03010000);
|
||||
|
||||
/* set some magic, and wait up to 1ms for it to appear */
|
||||
nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq);
|
||||
timeout = 1000;
|
||||
do {
|
||||
ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
|
||||
udelay(1);
|
||||
if (!timeout--) {
|
||||
AUX_ERR("magic wait 0x%08x\n", ctrl);
|
||||
auxch_fini(aux, ch);
|
||||
return -EBUSY;
|
||||
}
|
||||
} while ((ctrl & 0x03000000) != urep);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)
|
||||
{
|
||||
struct nouveau_i2c *aux = nouveau_i2c(base);
|
||||
struct nv50_i2c_port *port = (void *)base;
|
||||
u32 ctrl, stat, timeout, retries;
|
||||
u32 xbuf[4] = {};
|
||||
int ch = port->addr;
|
||||
int ret, i;
|
||||
|
||||
AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
|
||||
|
||||
ret = auxch_init(aux, ch);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
stat = nv_rd32(aux, 0x00e4e8 + (ch * 0x50));
|
||||
if (!(stat & 0x10000000)) {
|
||||
AUX_DBG("sink not detected\n");
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(type & 1)) {
|
||||
memcpy(xbuf, data, size);
|
||||
for (i = 0; i < 16; i += 4) {
|
||||
AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
|
||||
nv_wr32(aux, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]);
|
||||
}
|
||||
}
|
||||
|
||||
ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
|
||||
ctrl &= ~0x0001f0ff;
|
||||
ctrl |= type << 12;
|
||||
ctrl |= size - 1;
|
||||
nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr);
|
||||
|
||||
/* retry transaction a number of times on failure... */
|
||||
ret = -EREMOTEIO;
|
||||
for (retries = 0; retries < 32; retries++) {
|
||||
/* reset, and delay a while if this is a retry */
|
||||
nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
|
||||
nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl);
|
||||
if (retries)
|
||||
udelay(400);
|
||||
|
||||
/* transaction request, wait up to 1ms for it to complete */
|
||||
nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl);
|
||||
|
||||
timeout = 1000;
|
||||
do {
|
||||
ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
|
||||
udelay(1);
|
||||
if (!timeout--) {
|
||||
AUX_ERR("tx req timeout 0x%08x\n", ctrl);
|
||||
goto out;
|
||||
}
|
||||
} while (ctrl & 0x00010000);
|
||||
|
||||
/* read status, and check if transaction completed ok */
|
||||
stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0);
|
||||
if (!(stat & 0x000f0f00)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
|
||||
}
|
||||
|
||||
if (type & 1) {
|
||||
for (i = 0; i < 16; i += 4) {
|
||||
xbuf[i / 4] = nv_rd32(aux, 0x00e4d0 + (ch * 0x50) + i);
|
||||
AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
|
||||
}
|
||||
memcpy(data, xbuf, size);
|
||||
}
|
||||
|
||||
out:
|
||||
auxch_fini(aux, ch);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
nv94_i2c_acquire(struct nouveau_i2c_port *base)
|
||||
{
|
||||
struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
|
||||
struct nv50_i2c_port *port = (void *)base;
|
||||
if (port->ctrl) {
|
||||
nv_mask(priv, port->ctrl + 0x0c, 0x00000001, 0x00000000);
|
||||
nv_mask(priv, port->ctrl + 0x00, 0x0000f003, port->data);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nv94_i2c_release(struct nouveau_i2c_port *base)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct nouveau_i2c_func
|
||||
nv94_i2c_func = {
|
||||
.acquire = nv94_i2c_acquire,
|
||||
.release = nv94_i2c_release,
|
||||
.drive_scl = nv50_i2c_drive_scl,
|
||||
.drive_sda = nv50_i2c_drive_sda,
|
||||
.sense_scl = nv50_i2c_sense_scl,
|
||||
.sense_sda = nv50_i2c_sense_sda,
|
||||
};
|
||||
|
||||
static int
|
||||
nv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 index,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct dcb_i2c_entry *info = data;
|
||||
struct nv50_i2c_port *port;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_i2c_port_create(parent, engine, oclass, index,
|
||||
&nouveau_i2c_bit_algo, &port);
|
||||
*pobject = nv_object(port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (info->drive >= nv50_i2c_addr_nr)
|
||||
return -EINVAL;
|
||||
|
||||
port->base.func = &nv94_i2c_func;
|
||||
port->state = 7;
|
||||
port->addr = nv50_i2c_addr[info->drive];
|
||||
if (info->share != DCB_I2C_UNUSED) {
|
||||
port->ctrl = 0x00e500 + (info->share * 0x50);
|
||||
port->data = 0x0000e001;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct nouveau_i2c_func
|
||||
nv94_aux_func = {
|
||||
.acquire = nv94_i2c_acquire,
|
||||
.release = nv94_i2c_release,
|
||||
.aux = nv94_aux,
|
||||
};
|
||||
|
||||
int
|
||||
nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 index,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct dcb_i2c_entry *info = data;
|
||||
struct nv50_i2c_port *port;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_i2c_port_create(parent, engine, oclass, index,
|
||||
&nouveau_i2c_aux_algo, &port);
|
||||
*pobject = nv_object(port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
port->base.func = &nv94_aux_func;
|
||||
port->addr = info->drive;
|
||||
if (info->share != DCB_I2C_UNUSED) {
|
||||
port->ctrl = 0x00e500 + (info->drive * 0x50);
|
||||
port->data = 0x00002002;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv94_i2c_sclass[] = {
|
||||
{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv94_i2c_port_ctor,
|
||||
.dtor = _nouveau_i2c_port_dtor,
|
||||
.init = nv50_i2c_port_init,
|
||||
.fini = _nouveau_i2c_port_fini,
|
||||
},
|
||||
},
|
||||
{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv94_aux_port_ctor,
|
||||
.dtor = _nouveau_i2c_port_dtor,
|
||||
.init = _nouveau_i2c_port_init,
|
||||
.fini = _nouveau_i2c_port_fini,
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static int
|
||||
nv94_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv50_i2c_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_i2c_create(parent, engine, oclass, nv94_i2c_sclass, &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nouveau_oclass
|
||||
nv94_i2c_oclass = {
|
||||
.handle = NV_SUBDEV(I2C, 0x94),
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nv94_i2c_ctor,
|
||||
.dtor = _nouveau_i2c_dtor,
|
||||
.init = _nouveau_i2c_init,
|
||||
.fini = _nouveau_i2c_fini,
|
||||
},
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user