1 /* 2 * Copyright 2012 Red Hat Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: Ben Skeggs 23 */ 24 #include <subdev/bios.h> 25 #include <subdev/bios/dcb.h> 26 #include <subdev/bios/gpio.h> 27 #include <subdev/bios/xpio.h> 28 29 u16 30 dcb_gpio_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) 31 { 32 u16 data = 0x0000; 33 u16 dcb = dcb_table(bios, ver, hdr, cnt, len); 34 if (dcb) { 35 if (*ver >= 0x30 && *hdr >= 0x0c) 36 data = nv_ro16(bios, dcb + 0x0a); 37 else 38 if (*ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13) 39 data = nv_ro16(bios, dcb - 0x0f); 40 41 if (data) { 42 *ver = nv_ro08(bios, data + 0x00); 43 if (*ver < 0x30) { 44 *hdr = 3; 45 *cnt = nv_ro08(bios, data + 0x02); 46 *len = nv_ro08(bios, data + 0x01); 47 } else 48 if (*ver <= 0x41) { 49 *hdr = nv_ro08(bios, data + 0x01); 50 *cnt = nv_ro08(bios, data + 0x02); 51 *len = nv_ro08(bios, data + 0x03); 52 } else { 53 data = 0x0000; 54 } 55 } 56 } 57 return data; 58 } 59 60 u16 61 dcb_gpio_entry(struct nvkm_bios *bios, int idx, int ent, u8 *ver, u8 *len) 62 { 63 u8 hdr, cnt, xver; /* use gpio version for xpio entry parsing */ 64 u16 gpio; 65 66 if (!idx--) 67 gpio = dcb_gpio_table(bios, ver, &hdr, &cnt, len); 68 else 69 gpio = dcb_xpio_table(bios, idx, &xver, &hdr, &cnt, len); 70 71 if (gpio && ent < cnt) 72 return gpio + hdr + (ent * *len); 73 74 return 0x0000; 75 } 76 77 u16 78 dcb_gpio_parse(struct nvkm_bios *bios, int idx, int ent, u8 *ver, u8 *len, 79 struct dcb_gpio_func *gpio) 80 { 81 u16 data = dcb_gpio_entry(bios, idx, ent, ver, len); 82 if (data) { 83 if (*ver < 0x40) { 84 u16 info = nv_ro16(bios, data); 85 *gpio = (struct dcb_gpio_func) { 86 .line = (info & 0x001f) >> 0, 87 .func = (info & 0x07e0) >> 5, 88 .log[0] = (info & 0x1800) >> 11, 89 .log[1] = (info & 0x6000) >> 13, 90 .param = !!(info & 0x8000), 91 }; 92 } else 93 if (*ver < 0x41) { 94 u32 info = nv_ro32(bios, data); 95 *gpio = (struct dcb_gpio_func) { 96 .line = (info & 0x0000001f) >> 0, 97 .func = (info & 0x0000ff00) >> 8, 98 .log[0] = (info & 0x18000000) >> 27, 99 .log[1] = (info & 0x60000000) >> 29, 100 .param = !!(info & 0x80000000), 101 }; 102 } else { 103 u32 info = nv_ro32(bios, data + 0); 104 u8 info1 = nv_ro32(bios, data + 4); 105 *gpio = (struct dcb_gpio_func) { 106 .line = (info & 0x0000003f) >> 0, 107 .func = (info & 0x0000ff00) >> 8, 108 .log[0] = (info1 & 0x30) >> 4, 109 .log[1] = (info1 & 0xc0) >> 6, 110 .param = !!(info & 0x80000000), 111 }; 112 } 113 } 114 115 return data; 116 } 117 118 u16 119 dcb_gpio_match(struct nvkm_bios *bios, int idx, u8 func, u8 line, 120 u8 *ver, u8 *len, struct dcb_gpio_func *gpio) 121 { 122 u8 hdr, cnt, i = 0; 123 u16 data; 124 125 while ((data = dcb_gpio_parse(bios, idx, i++, ver, len, gpio))) { 126 if ((line == 0xff || line == gpio->line) && 127 (func == 0xff || func == gpio->func)) 128 return data; 129 } 130 131 /* DCB 2.2, fixed TVDAC GPIO data */ 132 if ((data = dcb_table(bios, ver, &hdr, &cnt, len))) { 133 if (*ver >= 0x22 && *ver < 0x30 && func == DCB_GPIO_TVDAC0) { 134 u8 conf = nv_ro08(bios, data - 5); 135 u8 addr = nv_ro08(bios, data - 4); 136 if (conf & 0x01) { 137 *gpio = (struct dcb_gpio_func) { 138 .func = DCB_GPIO_TVDAC0, 139 .line = addr >> 4, 140 .log[0] = !!(conf & 0x02), 141 .log[1] = !(conf & 0x02), 142 }; 143 *ver = 0x00; 144 return data; 145 } 146 } 147 } 148 149 return 0x0000; 150 } 151