/* * Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * arch/arm/mach-tegra/board-info.c * Parse kernel commandline (skuinfo, prodinfo and board_id info parsed here) */ #include #include #include #include "board.h" #include #include /* skuinfo is 18 character long xxx-xxxxx-xxxx-xxx *so buffer size is set to 18+1 */ #define SKUINFO_BUF_SIZE 19 /* skuver is 2 character long XX so buffer size is set to 2+1 */ #define SKUVER_BUF_SIZE 3 /* prodinfo is 18 character long xxx-xxxxx-xxxx-xxx * so buffer size is set to 18+1 */ #define PRODINFO_BUF_SIZE 19 /* prodver is 2 character long XX so buffer size is set to 2+1 */ #define PRODVER_BUF_SIZE 3 /* board_id is 23 character long xxx-xxxxx-xxxx-xxx-XY.ZZ * so buffer size is set to 24+1 */ #define BOARD_ID_BUF_SIZE 25 extern unsigned int system_serial_low; extern unsigned int system_serial_high; static unsigned int board_serial_low; static unsigned int board_serial_high; static char prodinfo_buffer[PRODINFO_BUF_SIZE]; static char prodver_buffer[PRODVER_BUF_SIZE]; static char skuinfo_buffer[SKUINFO_BUF_SIZE]; static char skuver_buffer[SKUVER_BUF_SIZE]; static int board_id_iterator __initdata; static struct tegra_board_info board_info_array[TEGRA_MAX_BOARDS]; static int __init board_id_setup(char *line) { char board_id[BOARD_ID_BUF_SIZE] = {0}; char *traverser = board_id; int delimiter_index; if (board_id_iterator >= TEGRA_MAX_BOARDS) { pr_warn("Number of Board Id's more than Max Boards defined\n"); return 0; } memset(&board_info_array[board_id_iterator], 0, sizeof(board_info_array[board_id_iterator])); strncpy(board_id, line, BOARD_ID_BUF_SIZE); board_id[BOARD_ID_BUF_SIZE - 1] = '\0'; board_info_array[board_id_iterator].valid = 1; delimiter_index = strcspn(traverser, "-"); memcpy(board_info_array[board_id_iterator].bom, traverser, delimiter_index); traverser += delimiter_index + 1; delimiter_index = strcspn(traverser, "-"); memcpy(board_info_array[board_id_iterator].project, traverser, delimiter_index); traverser += delimiter_index + 1; delimiter_index = strcspn(traverser, "-"); memcpy(board_info_array[board_id_iterator].sku, traverser, delimiter_index); traverser += delimiter_index + 1; delimiter_index = strcspn(traverser, "-"); memcpy(board_info_array[board_id_iterator].revision, traverser, delimiter_index); traverser += delimiter_index + 1; delimiter_index = strcspn(traverser, "-\0"); memcpy(board_info_array[board_id_iterator].bom_version, traverser, delimiter_index); traverser += delimiter_index + 1; board_id_iterator++; return 1; } __setup("board_id=", board_id_setup); static int __init sku_info_setup(char *line) { memcpy(skuinfo_buffer, line, SKUINFO_BUF_SIZE); return 1; } __setup("nvsku=", sku_info_setup); static int __init sku_ver_setup(char *line) { memcpy(skuver_buffer, line, SKUVER_BUF_SIZE); return 1; } __setup("SkuVer=", sku_ver_setup); static int __init prod_info_setup(char *line) { memcpy(prodinfo_buffer, line, PRODINFO_BUF_SIZE); return 1; } __setup("ProdInfo=", prod_info_setup); static int __init prod_ver_setup(char *line) { memcpy(prodver_buffer, line, PRODVER_BUF_SIZE); return 1; } __setup("ProdVer=", prod_ver_setup); static int read_skuinfo_proc_show(struct seq_file *m, void *v) { seq_printf(m, "%s\n", skuinfo_buffer); return 0; } static int read_skuinfo_proc_open(struct inode *inode, struct file *file) { return single_open(file, read_skuinfo_proc_show, NULL); } static const struct file_operations read_skuinfo_proc_fops = { .open = read_skuinfo_proc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int read_skuver_proc_show(struct seq_file *m, void *v) { seq_printf(m, "%s\n", skuver_buffer); return 0; } static int read_skuver_proc_open(struct inode *inode, struct file *file) { return single_open(file, read_skuver_proc_show, NULL); } static const struct file_operations read_skuver_proc_fops = { .open = read_skuver_proc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int read_serialinfo_proc_show(struct seq_file *m, void *v) { seq_printf(m, "%013llu\n", (((unsigned long long int)board_serial_high) << 32) | board_serial_low); return 0; } static int read_serialinfo_proc_open(struct inode *inode, struct file *file) { return single_open(file, read_serialinfo_proc_show, NULL); } static const struct file_operations read_serialinfo_proc_fops = { .open = read_serialinfo_proc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int read_prodinfo_proc_show(struct seq_file *m, void *v) { seq_printf(m, "%s\n", prodinfo_buffer); return 0; } static int read_prodinfo_proc_open(struct inode *inode, struct file *file) { return single_open(file, read_prodinfo_proc_show, NULL); } static const struct file_operations read_prodinfo_proc_fops = { .open = read_prodinfo_proc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int read_prodver_proc_show(struct seq_file *m, void *v) { seq_printf(m, "%s\n", prodver_buffer); return 0; } static int read_prodver_proc_open(struct inode *inode, struct file *file) { return single_open(file, read_prodver_proc_show, NULL); } static const struct file_operations read_prodver_proc_fops = { .open = read_prodver_proc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; int __init tegra_init_board_info(void) { board_serial_low = system_serial_low; board_serial_high = system_serial_high; if (!proc_create("board_serial", 0, NULL, &read_serialinfo_proc_fops)) { printk(KERN_ERR "Can't create proc entry for board_serial!\n"); return -1; } if (!proc_create("skuinfo", 0, NULL, &read_skuinfo_proc_fops)) { printk(KERN_ERR "Can't create proc entry for skuinfo!\n"); return -1; } if (!proc_create("skuver", 0, NULL, &read_skuver_proc_fops)) { printk(KERN_ERR "Can't create proc entry for skuver!\n"); return -1; } if (!proc_create("prodinfo", 0, NULL, &read_prodinfo_proc_fops)) { printk(KERN_ERR "Can't create proc entry for prodinfo!\n"); return -1; } if (!proc_create("prodver", 0, NULL, &read_prodver_proc_fops)) { printk(KERN_ERR "Can't create proc entry for prodver!\n"); return -1; } return 0; } bool tegra_is_board(const char *bom, const char *project, const char *sku, const char *revision, const char *bom_version) { int i = 0; bool b = true; while (i < TEGRA_MAX_BOARDS && board_info_array[i].valid != 0) { b = (!bom || !strncmp(board_info_array[i].bom, bom, MAX_BUFFER)) && (!project || !strncmp(board_info_array[i].project, project, MAX_BUFFER)) && (!sku || !strncmp(board_info_array[i].sku, sku, MAX_BUFFER)) && (!revision || !strncmp(board_info_array[i].revision, revision, MAX_BUFFER)) && (!bom_version || !strncmp(board_info_array[i].bom_version, bom_version, MAX_BUFFER)); if (b) return true; i++; } return false; } EXPORT_SYMBOL(tegra_is_board); bool is_tegra_diagnostic_mode(void) { static bool is_mode_valid; static bool is_diagnostic_mode; if (!is_mode_valid) { is_diagnostic_mode = of_property_read_bool(of_chosen, "nvidia,tegra-diagnostic-mode"); is_mode_valid = true; } return is_diagnostic_mode; } EXPORT_SYMBOL(is_tegra_diagnostic_mode);