1c39f472eSBen Skeggs /* 2c39f472eSBen Skeggs * Copyright 2012 Red Hat Inc. 3c39f472eSBen Skeggs * 4c39f472eSBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a 5c39f472eSBen Skeggs * copy of this software and associated documentation files (the "Software"), 6c39f472eSBen Skeggs * to deal in the Software without restriction, including without limitation 7c39f472eSBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8c39f472eSBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the 9c39f472eSBen Skeggs * Software is furnished to do so, subject to the following conditions: 10c39f472eSBen Skeggs * 11c39f472eSBen Skeggs * The above copyright notice and this permission notice shall be included in 12c39f472eSBen Skeggs * all copies or substantial portions of the Software. 13c39f472eSBen Skeggs * 14c39f472eSBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15c39f472eSBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16c39f472eSBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17c39f472eSBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18c39f472eSBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19c39f472eSBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20c39f472eSBen Skeggs * OTHER DEALINGS IN THE SOFTWARE. 21c39f472eSBen Skeggs * 22c39f472eSBen Skeggs * Authors: Ben Skeggs 23c39f472eSBen Skeggs */ 24c39f472eSBen Skeggs 25c39f472eSBen Skeggs #include "core/device.h" 26c39f472eSBen Skeggs 27c39f472eSBen Skeggs #include "subdev/bios.h" 28c39f472eSBen Skeggs #include "subdev/bios/dcb.h" 29c39f472eSBen Skeggs 30c39f472eSBen Skeggs u16 31c39f472eSBen Skeggs dcb_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) 32c39f472eSBen Skeggs { 33c39f472eSBen Skeggs struct nouveau_device *device = nv_device(bios); 34c39f472eSBen Skeggs u16 dcb = 0x0000; 35c39f472eSBen Skeggs 36c39f472eSBen Skeggs if (device->card_type > NV_04) 37c39f472eSBen Skeggs dcb = nv_ro16(bios, 0x36); 38c39f472eSBen Skeggs if (!dcb) { 39c39f472eSBen Skeggs nv_warn(bios, "DCB table not found\n"); 40c39f472eSBen Skeggs return dcb; 41c39f472eSBen Skeggs } 42c39f472eSBen Skeggs 43c39f472eSBen Skeggs *ver = nv_ro08(bios, dcb); 44c39f472eSBen Skeggs 45c39f472eSBen Skeggs if (*ver >= 0x42) { 46c39f472eSBen Skeggs nv_warn(bios, "DCB version 0x%02x unknown\n", *ver); 47c39f472eSBen Skeggs return 0x0000; 48c39f472eSBen Skeggs } else 49c39f472eSBen Skeggs if (*ver >= 0x30) { 50c39f472eSBen Skeggs if (nv_ro32(bios, dcb + 6) == 0x4edcbdcb) { 51c39f472eSBen Skeggs *hdr = nv_ro08(bios, dcb + 1); 52c39f472eSBen Skeggs *cnt = nv_ro08(bios, dcb + 2); 53c39f472eSBen Skeggs *len = nv_ro08(bios, dcb + 3); 54c39f472eSBen Skeggs return dcb; 55c39f472eSBen Skeggs } 56c39f472eSBen Skeggs } else 57c39f472eSBen Skeggs if (*ver >= 0x20) { 58c39f472eSBen Skeggs if (nv_ro32(bios, dcb + 4) == 0x4edcbdcb) { 59c39f472eSBen Skeggs u16 i2c = nv_ro16(bios, dcb + 2); 60c39f472eSBen Skeggs *hdr = 8; 61c39f472eSBen Skeggs *cnt = (i2c - dcb) / 8; 62c39f472eSBen Skeggs *len = 8; 63c39f472eSBen Skeggs return dcb; 64c39f472eSBen Skeggs } 65c39f472eSBen Skeggs } else 66c39f472eSBen Skeggs if (*ver >= 0x15) { 67c39f472eSBen Skeggs if (!nv_memcmp(bios, dcb - 7, "DEV_REC", 7)) { 68c39f472eSBen Skeggs u16 i2c = nv_ro16(bios, dcb + 2); 69c39f472eSBen Skeggs *hdr = 4; 70c39f472eSBen Skeggs *cnt = (i2c - dcb) / 10; 71c39f472eSBen Skeggs *len = 10; 72c39f472eSBen Skeggs return dcb; 73c39f472eSBen Skeggs } 74c39f472eSBen Skeggs } else { 75c39f472eSBen Skeggs /* 76c39f472eSBen Skeggs * v1.4 (some NV15/16, NV11+) seems the same as v1.5, but 77c39f472eSBen Skeggs * always has the same single (crt) entry, even when tv-out 78c39f472eSBen Skeggs * present, so the conclusion is this version cannot really 79c39f472eSBen Skeggs * be used. 80c39f472eSBen Skeggs * 81c39f472eSBen Skeggs * v1.2 tables (some NV6/10, and NV15+) normally have the 82c39f472eSBen Skeggs * same 5 entries, which are not specific to the card and so 83c39f472eSBen Skeggs * no use. 84c39f472eSBen Skeggs * 85c39f472eSBen Skeggs * v1.2 does have an I2C table that read_dcb_i2c_table can 86c39f472eSBen Skeggs * handle, but cards exist (nv11 in #14821) with a bad i2c 87c39f472eSBen Skeggs * table pointer, so use the indices parsed in 88c39f472eSBen Skeggs * parse_bmp_structure. 89c39f472eSBen Skeggs * 90c39f472eSBen Skeggs * v1.1 (NV5+, maybe some NV4) is entirely unhelpful 91c39f472eSBen Skeggs */ 92c39f472eSBen Skeggs nv_warn(bios, "DCB contains no useful data\n"); 93c39f472eSBen Skeggs return 0x0000; 94c39f472eSBen Skeggs } 95c39f472eSBen Skeggs 96c39f472eSBen Skeggs nv_warn(bios, "DCB header validation failed\n"); 97c39f472eSBen Skeggs return 0x0000; 98c39f472eSBen Skeggs } 99c39f472eSBen Skeggs 100c39f472eSBen Skeggs u16 101c39f472eSBen Skeggs dcb_outp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) 102c39f472eSBen Skeggs { 103c39f472eSBen Skeggs u8 hdr, cnt; 104c39f472eSBen Skeggs u16 dcb = dcb_table(bios, ver, &hdr, &cnt, len); 105c39f472eSBen Skeggs if (dcb && idx < cnt) 106c39f472eSBen Skeggs return dcb + hdr + (idx * *len); 107c39f472eSBen Skeggs return 0x0000; 108c39f472eSBen Skeggs } 109c39f472eSBen Skeggs 110c39f472eSBen Skeggs static inline u16 111c39f472eSBen Skeggs dcb_outp_hasht(struct dcb_output *outp) 112c39f472eSBen Skeggs { 113c39f472eSBen Skeggs return (outp->extdev << 8) | (outp->location << 4) | outp->type; 114c39f472eSBen Skeggs } 115c39f472eSBen Skeggs 116c39f472eSBen Skeggs static inline u16 117c39f472eSBen Skeggs dcb_outp_hashm(struct dcb_output *outp) 118c39f472eSBen Skeggs { 119c39f472eSBen Skeggs return (outp->heads << 8) | (outp->link << 6) | outp->or; 120c39f472eSBen Skeggs } 121c39f472eSBen Skeggs 122c39f472eSBen Skeggs u16 123c39f472eSBen Skeggs dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len, 124c39f472eSBen Skeggs struct dcb_output *outp) 125c39f472eSBen Skeggs { 126c39f472eSBen Skeggs u16 dcb = dcb_outp(bios, idx, ver, len); 127c39f472eSBen Skeggs memset(outp, 0x00, sizeof(*outp)); 128c39f472eSBen Skeggs if (dcb) { 129c39f472eSBen Skeggs if (*ver >= 0x20) { 130c39f472eSBen Skeggs u32 conn = nv_ro32(bios, dcb + 0x00); 131c39f472eSBen Skeggs outp->or = (conn & 0x0f000000) >> 24; 132c39f472eSBen Skeggs outp->location = (conn & 0x00300000) >> 20; 133c39f472eSBen Skeggs outp->bus = (conn & 0x000f0000) >> 16; 134c39f472eSBen Skeggs outp->connector = (conn & 0x0000f000) >> 12; 135c39f472eSBen Skeggs outp->heads = (conn & 0x00000f00) >> 8; 136c39f472eSBen Skeggs outp->i2c_index = (conn & 0x000000f0) >> 4; 137c39f472eSBen Skeggs outp->type = (conn & 0x0000000f); 138c39f472eSBen Skeggs outp->link = 0; 139c39f472eSBen Skeggs } else { 140c39f472eSBen Skeggs dcb = 0x0000; 141c39f472eSBen Skeggs } 142c39f472eSBen Skeggs 143c39f472eSBen Skeggs if (*ver >= 0x40) { 144c39f472eSBen Skeggs u32 conf = nv_ro32(bios, dcb + 0x04); 145c39f472eSBen Skeggs switch (outp->type) { 146c39f472eSBen Skeggs case DCB_OUTPUT_DP: 147c39f472eSBen Skeggs switch (conf & 0x00e00000) { 148c39f472eSBen Skeggs case 0x00000000: 149c39f472eSBen Skeggs outp->dpconf.link_bw = 0x06; 150c39f472eSBen Skeggs break; 151c39f472eSBen Skeggs case 0x00200000: 152c39f472eSBen Skeggs outp->dpconf.link_bw = 0x0a; 153c39f472eSBen Skeggs break; 154c39f472eSBen Skeggs case 0x00400000: 155c39f472eSBen Skeggs default: 156c39f472eSBen Skeggs outp->dpconf.link_bw = 0x14; 157c39f472eSBen Skeggs break; 158c39f472eSBen Skeggs } 159c39f472eSBen Skeggs 160c39f472eSBen Skeggs outp->dpconf.link_nr = (conf & 0x0f000000) >> 24; 161c39f472eSBen Skeggs if (*ver < 0x41) { 162c39f472eSBen Skeggs switch (outp->dpconf.link_nr) { 163c39f472eSBen Skeggs case 0x0f: 164c39f472eSBen Skeggs outp->dpconf.link_nr = 4; 165c39f472eSBen Skeggs break; 166c39f472eSBen Skeggs case 0x03: 167c39f472eSBen Skeggs outp->dpconf.link_nr = 2; 168c39f472eSBen Skeggs break; 169c39f472eSBen Skeggs case 0x01: 170c39f472eSBen Skeggs default: 171c39f472eSBen Skeggs outp->dpconf.link_nr = 1; 172c39f472eSBen Skeggs break; 173c39f472eSBen Skeggs } 174c39f472eSBen Skeggs } 175c39f472eSBen Skeggs 176c39f472eSBen Skeggs /* fall-through... */ 177c39f472eSBen Skeggs case DCB_OUTPUT_TMDS: 178c39f472eSBen Skeggs case DCB_OUTPUT_LVDS: 179c39f472eSBen Skeggs outp->link = (conf & 0x00000030) >> 4; 180c39f472eSBen Skeggs outp->sorconf.link = outp->link; /*XXX*/ 181c39f472eSBen Skeggs outp->extdev = 0x00; 182c39f472eSBen Skeggs if (outp->location != 0) 183c39f472eSBen Skeggs outp->extdev = (conf & 0x0000ff00) >> 8; 184c39f472eSBen Skeggs break; 185c39f472eSBen Skeggs default: 186c39f472eSBen Skeggs break; 187c39f472eSBen Skeggs } 188c39f472eSBen Skeggs } 189c39f472eSBen Skeggs 190c39f472eSBen Skeggs outp->hasht = dcb_outp_hasht(outp); 191c39f472eSBen Skeggs outp->hashm = dcb_outp_hashm(outp); 192c39f472eSBen Skeggs } 193c39f472eSBen Skeggs return dcb; 194c39f472eSBen Skeggs } 195c39f472eSBen Skeggs 196c39f472eSBen Skeggs u16 197c39f472eSBen Skeggs dcb_outp_match(struct nouveau_bios *bios, u16 type, u16 mask, 198c39f472eSBen Skeggs u8 *ver, u8 *len, struct dcb_output *outp) 199c39f472eSBen Skeggs { 200c39f472eSBen Skeggs u16 dcb, idx = 0; 201c39f472eSBen Skeggs while ((dcb = dcb_outp_parse(bios, idx++, ver, len, outp))) { 202c39f472eSBen Skeggs if ((dcb_outp_hasht(outp) & 0x00ff) == (type & 0x00ff)) { 203c39f472eSBen Skeggs if ((dcb_outp_hashm(outp) & mask) == mask) 204c39f472eSBen Skeggs break; 205c39f472eSBen Skeggs } 206c39f472eSBen Skeggs } 207c39f472eSBen Skeggs return dcb; 208c39f472eSBen Skeggs } 209c39f472eSBen Skeggs 210c39f472eSBen Skeggs int 211c39f472eSBen Skeggs dcb_outp_foreach(struct nouveau_bios *bios, void *data, 212c39f472eSBen Skeggs int (*exec)(struct nouveau_bios *, void *, int, u16)) 213c39f472eSBen Skeggs { 214c39f472eSBen Skeggs int ret, idx = -1; 215c39f472eSBen Skeggs u8 ver, len; 216c39f472eSBen Skeggs u16 outp; 217c39f472eSBen Skeggs 218c39f472eSBen Skeggs while ((outp = dcb_outp(bios, ++idx, &ver, &len))) { 219c39f472eSBen Skeggs if (nv_ro32(bios, outp) == 0x00000000) 220c39f472eSBen Skeggs break; /* seen on an NV11 with DCB v1.5 */ 221c39f472eSBen Skeggs if (nv_ro32(bios, outp) == 0xffffffff) 222c39f472eSBen Skeggs break; /* seen on an NV17 with DCB v2.0 */ 223c39f472eSBen Skeggs 224c39f472eSBen Skeggs if (nv_ro08(bios, outp) == DCB_OUTPUT_UNUSED) 225c39f472eSBen Skeggs continue; 226c39f472eSBen Skeggs if (nv_ro08(bios, outp) == DCB_OUTPUT_EOL) 227c39f472eSBen Skeggs break; 228c39f472eSBen Skeggs 229c39f472eSBen Skeggs ret = exec(bios, data, idx, outp); 230c39f472eSBen Skeggs if (ret) 231c39f472eSBen Skeggs return ret; 232c39f472eSBen Skeggs } 233c39f472eSBen Skeggs 234c39f472eSBen Skeggs return 0; 235c39f472eSBen Skeggs } 236