nouveau_nvkm_subdev_bios_base.c revision 1.1
1/* $NetBSD: nouveau_nvkm_subdev_bios_base.c,v 1.1 2018/08/27 01:34:56 riastradh Exp $ */ 2 3/* 4 * Copyright 2012 Red Hat Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: Ben Skeggs 25 */ 26#include <sys/cdefs.h> 27__KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_subdev_bios_base.c,v 1.1 2018/08/27 01:34:56 riastradh Exp $"); 28 29#include "priv.h" 30 31#include <subdev/bios.h> 32#include <subdev/bios/bmp.h> 33#include <subdev/bios/bit.h> 34 35u8 36nvbios_checksum(const u8 *data, int size) 37{ 38 u8 sum = 0; 39 while (size--) 40 sum += *data++; 41 return sum; 42} 43 44u16 45nvbios_findstr(const u8 *data, int size, const char *str, int len) 46{ 47 int i, j; 48 49 for (i = 0; i <= (size - len); i++) { 50 for (j = 0; j < len; j++) 51 if ((char)data[i + j] != str[j]) 52 break; 53 if (j == len) 54 return i; 55 } 56 57 return 0; 58} 59 60int 61nvbios_memcmp(struct nvkm_bios *bios, u32 addr, const char *str, u32 len) 62{ 63 unsigned char c1, c2; 64 65 while (len--) { 66 c1 = nvbios_rd08(bios, addr++); 67 c2 = *(str++); 68 if (c1 != c2) 69 return c1 - c2; 70 } 71 return 0; 72} 73 74int 75nvbios_extend(struct nvkm_bios *bios, u32 length) 76{ 77 if (bios->size < length) { 78 u8 *prev = bios->data; 79 if (!(bios->data = kmalloc(length, GFP_KERNEL))) { 80 bios->data = prev; 81 return -ENOMEM; 82 } 83 memcpy(bios->data, prev, bios->size); 84 bios->size = length; 85 kfree(prev); 86 return 1; 87 } 88 return 0; 89} 90 91static void * 92nvkm_bios_dtor(struct nvkm_subdev *subdev) 93{ 94 struct nvkm_bios *bios = nvkm_bios(subdev); 95 kfree(bios->data); 96 return bios; 97} 98 99static const struct nvkm_subdev_func 100nvkm_bios = { 101 .dtor = nvkm_bios_dtor, 102}; 103 104int 105nvkm_bios_new(struct nvkm_device *device, int index, struct nvkm_bios **pbios) 106{ 107 struct nvkm_bios *bios; 108 struct bit_entry bit_i; 109 int ret; 110 111 if (!(bios = *pbios = kzalloc(sizeof(*bios), GFP_KERNEL))) 112 return -ENOMEM; 113 nvkm_subdev_ctor(&nvkm_bios, device, index, 0, &bios->subdev); 114 115 ret = nvbios_shadow(bios); 116 if (ret) 117 return ret; 118 119 /* detect type of vbios we're dealing with */ 120 bios->bmp_offset = nvbios_findstr(bios->data, bios->size, 121 "\xff\x7f""NV\0", 5); 122 if (bios->bmp_offset) { 123 nvkm_debug(&bios->subdev, "BMP version %x.%x\n", 124 bmp_version(bios) >> 8, 125 bmp_version(bios) & 0xff); 126 } 127 128 bios->bit_offset = nvbios_findstr(bios->data, bios->size, 129 "\xff\xb8""BIT", 5); 130 if (bios->bit_offset) 131 nvkm_debug(&bios->subdev, "BIT signature found\n"); 132 133 /* determine the vbios version number */ 134 if (!bit_entry(bios, 'i', &bit_i) && bit_i.length >= 4) { 135 bios->version.major = nvbios_rd08(bios, bit_i.offset + 3); 136 bios->version.chip = nvbios_rd08(bios, bit_i.offset + 2); 137 bios->version.minor = nvbios_rd08(bios, bit_i.offset + 1); 138 bios->version.micro = nvbios_rd08(bios, bit_i.offset + 0); 139 bios->version.patch = nvbios_rd08(bios, bit_i.offset + 4); 140 } else 141 if (bmp_version(bios)) { 142 bios->version.major = nvbios_rd08(bios, bios->bmp_offset + 13); 143 bios->version.chip = nvbios_rd08(bios, bios->bmp_offset + 12); 144 bios->version.minor = nvbios_rd08(bios, bios->bmp_offset + 11); 145 bios->version.micro = nvbios_rd08(bios, bios->bmp_offset + 10); 146 } 147 148 nvkm_info(&bios->subdev, "version %02x.%02x.%02x.%02x.%02x\n", 149 bios->version.major, bios->version.chip, 150 bios->version.minor, bios->version.micro, bios->version.patch); 151 return 0; 152} 153