Skip to content

Commit

Permalink
drm/nouveau: implement devinit subdev, and new init table parser
Browse files Browse the repository at this point in the history
v2:
- make sure not to execute display scripts unless resuming

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
  • Loading branch information
Ben Skeggs committed Oct 3, 2012
1 parent 70790f4 commit cb75d97
Show file tree
Hide file tree
Showing 54 changed files with 3,796 additions and 3,914 deletions.
10 changes: 10 additions & 0 deletions drivers/gpu/drm/nouveau/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ nouveau-y += core/core/subdev.o

nouveau-y += core/subdev/bios/base.o
nouveau-y += core/subdev/bios/bit.o
nouveau-y += core/subdev/bios/conn.o
nouveau-y += core/subdev/bios/dcb.o
nouveau-y += core/subdev/bios/dp.o
nouveau-y += core/subdev/bios/gpio.o
nouveau-y += core/subdev/bios/i2c.o
nouveau-y += core/subdev/bios/init.o
nouveau-y += core/subdev/bios/pll.o
nouveau-y += core/subdev/clock/nv04.o
nouveau-y += core/subdev/clock/nv40.o
Expand All @@ -40,6 +43,13 @@ nouveau-y += core/subdev/device/nv40.o
nouveau-y += core/subdev/device/nv50.o
nouveau-y += core/subdev/device/nvc0.o
nouveau-y += core/subdev/device/nve0.o
nouveau-y += core/subdev/devinit/base.o
nouveau-y += core/subdev/devinit/nv04.o
nouveau-y += core/subdev/devinit/nv05.o
nouveau-y += core/subdev/devinit/nv10.o
nouveau-y += core/subdev/devinit/nv1a.o
nouveau-y += core/subdev/devinit/nv20.o
nouveau-y += core/subdev/devinit/nv50.o
nouveau-y += core/subdev/fb/nv04.o
nouveau-y += core/subdev/fb/nv10.o
nouveau-y += core/subdev/fb/nv20.o
Expand Down
27 changes: 27 additions & 0 deletions drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef __NVBIOS_CONN_H__
#define __NVBIOS_CONN_H__

enum dcb_connector_type {
DCB_CONNECTOR_VGA = 0x00,
DCB_CONNECTOR_TV_0 = 0x10,
DCB_CONNECTOR_TV_1 = 0x11,
DCB_CONNECTOR_TV_3 = 0x13,
DCB_CONNECTOR_DVI_I = 0x30,
DCB_CONNECTOR_DVI_D = 0x31,
DCB_CONNECTOR_DMS59_0 = 0x38,
DCB_CONNECTOR_DMS59_1 = 0x39,
DCB_CONNECTOR_LVDS = 0x40,
DCB_CONNECTOR_LVDS_SPWG = 0x41,
DCB_CONNECTOR_DP = 0x46,
DCB_CONNECTOR_eDP = 0x47,
DCB_CONNECTOR_HDMI_0 = 0x60,
DCB_CONNECTOR_HDMI_1 = 0x61,
DCB_CONNECTOR_DMS59_DP0 = 0x64,
DCB_CONNECTOR_DMS59_DP1 = 0x65,
DCB_CONNECTOR_NONE = 0xff
};

u16 dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
u16 dcb_conn(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len);

#endif
73 changes: 72 additions & 1 deletion drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,90 @@
#ifndef __NVBIOS_DCB_H__
#define __NVBIOS_DCB_H__

struct nouveau_bios;

enum dcb_output_type {
DCB_OUTPUT_ANALOG = 0x0,
DCB_OUTPUT_TV = 0x1,
DCB_OUTPUT_TMDS = 0x2,
DCB_OUTPUT_LVDS = 0x3,
DCB_OUTPUT_DP = 0x4,
DCB_OUTPUT_DP = 0x6,
DCB_OUTPUT_EOL = 0xe,
DCB_OUTPUT_UNUSED = 0xf,
DCB_OUTPUT_ANY = -1,
};

struct dcb_output {
int index; /* may not be raw dcb index if merging has happened */
enum dcb_output_type type;
uint8_t i2c_index;
uint8_t heads;
uint8_t connector;
uint8_t bus;
uint8_t location;
uint8_t or;
bool duallink_possible;
union {
struct sor_conf {
int link;
} sorconf;
struct {
int maxfreq;
} crtconf;
struct {
struct sor_conf sor;
bool use_straps_for_mode;
bool use_acpi_for_edid;
bool use_power_scripts;
} lvdsconf;
struct {
bool has_component_output;
} tvconf;
struct {
struct sor_conf sor;
int link_nr;
int link_bw;
} dpconf;
struct {
struct sor_conf sor;
int slave_addr;
} tmdsconf;
};
bool i2c_upper_default;
};

u16 dcb_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *ent, u8 *len);
u16 dcb_outp(struct nouveau_bios *, u8 idx, u8 *ver, u8 *len);
int dcb_outp_foreach(struct nouveau_bios *, void *data, int (*exec)
(struct nouveau_bios *, void *, int index, u16 entry));


/* BIT 'U'/'d' table encoder subtables have hashes matching them to
* a particular set of encoders.
*
* This function returns true if a particular DCB entry matches.
*/
static inline bool
dcb_hash_match(struct dcb_output *dcb, u32 hash)
{
if ((hash & 0x000000f0) != (dcb->location << 4))
return false;
if ((hash & 0x0000000f) != dcb->type)
return false;
if (!(hash & (dcb->or << 16)))
return false;

switch (dcb->type) {
case DCB_OUTPUT_TMDS:
case DCB_OUTPUT_LVDS:
case DCB_OUTPUT_DP:
if (hash & 0x00c00000) {
if (!(hash & (dcb->sorconf.link << 22)))
return false;
}
default:
return true;
}
}

#endif
8 changes: 8 additions & 0 deletions drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef __NVBIOS_DP_H__
#define __NVBIOS_DP_H__

u16 dp_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
u16 dp_outp(struct nouveau_bios *, u8 idx, u8 *ver, u8 *len);
u16 dp_outp_match(struct nouveau_bios *, struct dcb_output *, u8 *ver, u8 *len);

#endif
21 changes: 21 additions & 0 deletions drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef __NVBIOS_INIT_H__
#define __NVBIOS_INIT_H__

struct nvbios_init {
struct nouveau_subdev *subdev;
struct nouveau_bios *bios;
u16 offset;
struct dcb_output *outp;
int crtc;

/* internal state used during parsing */
u8 execute;
u32 nested;
u16 repeat;
u16 repend;
};

int nvbios_exec(struct nvbios_init *);
int nvbios_init(struct nouveau_subdev *, bool execute);

#endif
40 changes: 40 additions & 0 deletions drivers/gpu/drm/nouveau/core/include/subdev/devinit.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef __NOUVEAU_DEVINIT_H__
#define __NOUVEAU_DEVINIT_H__

#include <core/subdev.h>
#include <core/device.h>

struct nouveau_devinit {
struct nouveau_subdev base;
bool post;
void (*meminit)(struct nouveau_devinit *);
};

static inline struct nouveau_devinit *
nouveau_devinit(void *obj)
{
return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_DEVINIT];
}

#define nouveau_devinit_create(p,e,o,d) \
nouveau_devinit_create_((p), (e), (o), sizeof(**d), (void **)d)
#define nouveau_devinit_destroy(p) \
nouveau_subdev_destroy(&(p)->base)

int nouveau_devinit_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, int, void **);
int nouveau_devinit_init(struct nouveau_devinit *);
int nouveau_devinit_fini(struct nouveau_devinit *, bool suspend);

extern struct nouveau_oclass nv04_devinit_oclass;
extern struct nouveau_oclass nv05_devinit_oclass;
extern struct nouveau_oclass nv10_devinit_oclass;
extern struct nouveau_oclass nv1a_devinit_oclass;
extern struct nouveau_oclass nv20_devinit_oclass;
extern struct nouveau_oclass nv50_devinit_oclass;

void nv04_devinit_dtor(struct nouveau_object *);
int nv04_devinit_init(struct nouveau_object *);
int nv04_devinit_fini(struct nouveau_object *, bool);

#endif
55 changes: 55 additions & 0 deletions drivers/gpu/drm/nouveau/core/subdev/bios/conn.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* 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/device.h>

#include <subdev/bios.h>
#include <subdev/bios/dcb.h>

u16
dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
{
u16 dcb = dcb_table(bios, ver, hdr, cnt, len);
if (dcb && *ver >= 0x30 && *hdr >= 0x16) {
u16 data = nv_ro16(bios, dcb + 0x14);
if (data) {
*ver = nv_ro08(bios, data + 0);
*hdr = nv_ro08(bios, data + 1);
*cnt = nv_ro08(bios, data + 2);
*len = nv_ro08(bios, data + 3);
return data;
}
}
return 0x0000;
}

u16
dcb_conn(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len)
{
u8 hdr, cnt;
u16 data = dcb_conntab(bios, ver, &hdr, &cnt, len);
if (data && idx < cnt)
return data + hdr + (idx * *len);
return 0x0000;
}
76 changes: 76 additions & 0 deletions drivers/gpu/drm/nouveau/core/subdev/bios/dp.c
Original file line number Diff line number Diff line change
@@ -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/bit.h"
#include "subdev/bios/dcb.h"
#include "subdev/bios/dp.h"

u16
dp_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
{
struct bit_entry bit_d;

if (!bit_entry(bios, 'd', &bit_d)) {
if (bit_d.version == 1) {
u16 data = nv_ro16(bios, bit_d.offset);
if (data) {
*ver = nv_ro08(bios, data + 0);
*hdr = nv_ro08(bios, data + 1);
*len = nv_ro08(bios, data + 2);
*cnt = nv_ro08(bios, data + 3);
return data;
}
}
}

return 0x0000;
}

u16
dp_outp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len)
{
u8 hdr, cnt;
u16 table = dp_table(bios, ver, &hdr, &cnt, len);
if (table && idx < cnt)
return nv_ro16(bios, table + hdr + (idx * *len));
return 0xffff;
}

u16
dp_outp_match(struct nouveau_bios *bios, struct dcb_output *outp,
u8 *ver, u8 *len)
{
u8 idx = 0;
u16 data;
while ((data = dp_outp(bios, idx++, ver, len)) != 0xffff) {
if (data) {
u32 hash = nv_ro32(bios, data);
if (dcb_hash_match(outp, hash))
return data;
}
}
return 0x0000;
}
Loading

0 comments on commit cb75d97

Please sign in to comment.