13683b761SEmmanuel Gil Peyrot // SPDX-License-Identifier: GPL-2.0-only 23683b761SEmmanuel Gil Peyrot /* 33683b761SEmmanuel Gil Peyrot * Nintendo Wii and Wii U OTP driver 43683b761SEmmanuel Gil Peyrot * 53683b761SEmmanuel Gil Peyrot * This is a driver exposing the OTP of a Nintendo Wii or Wii U console. 63683b761SEmmanuel Gil Peyrot * 73683b761SEmmanuel Gil Peyrot * This memory contains common and per-console keys, signatures and 83683b761SEmmanuel Gil Peyrot * related data required to access peripherals. 93683b761SEmmanuel Gil Peyrot * 103683b761SEmmanuel Gil Peyrot * Based on reversed documentation from https://wiiubrew.org/wiki/Hardware/OTP 113683b761SEmmanuel Gil Peyrot * 123683b761SEmmanuel Gil Peyrot * Copyright (C) 2021 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> 133683b761SEmmanuel Gil Peyrot */ 143683b761SEmmanuel Gil Peyrot 153683b761SEmmanuel Gil Peyrot #include <linux/device.h> 163683b761SEmmanuel Gil Peyrot #include <linux/io.h> 173683b761SEmmanuel Gil Peyrot #include <linux/module.h> 183683b761SEmmanuel Gil Peyrot #include <linux/mod_devicetable.h> 193683b761SEmmanuel Gil Peyrot #include <linux/nvmem-provider.h> 203683b761SEmmanuel Gil Peyrot #include <linux/of_device.h> 213683b761SEmmanuel Gil Peyrot #include <linux/platform_device.h> 223683b761SEmmanuel Gil Peyrot 233683b761SEmmanuel Gil Peyrot #define HW_OTPCMD 0 243683b761SEmmanuel Gil Peyrot #define HW_OTPDATA 4 253683b761SEmmanuel Gil Peyrot #define OTP_READ 0x80000000 263683b761SEmmanuel Gil Peyrot #define BANK_SIZE 128 273683b761SEmmanuel Gil Peyrot #define WORD_SIZE 4 283683b761SEmmanuel Gil Peyrot 293683b761SEmmanuel Gil Peyrot struct nintendo_otp_priv { 303683b761SEmmanuel Gil Peyrot void __iomem *regs; 313683b761SEmmanuel Gil Peyrot }; 323683b761SEmmanuel Gil Peyrot 333683b761SEmmanuel Gil Peyrot struct nintendo_otp_devtype_data { 343683b761SEmmanuel Gil Peyrot const char *name; 353683b761SEmmanuel Gil Peyrot unsigned int num_banks; 363683b761SEmmanuel Gil Peyrot }; 373683b761SEmmanuel Gil Peyrot 383683b761SEmmanuel Gil Peyrot static const struct nintendo_otp_devtype_data hollywood_otp_data = { 393683b761SEmmanuel Gil Peyrot .name = "wii-otp", 403683b761SEmmanuel Gil Peyrot .num_banks = 1, 413683b761SEmmanuel Gil Peyrot }; 423683b761SEmmanuel Gil Peyrot 433683b761SEmmanuel Gil Peyrot static const struct nintendo_otp_devtype_data latte_otp_data = { 443683b761SEmmanuel Gil Peyrot .name = "wiiu-otp", 453683b761SEmmanuel Gil Peyrot .num_banks = 8, 463683b761SEmmanuel Gil Peyrot }; 473683b761SEmmanuel Gil Peyrot 483683b761SEmmanuel Gil Peyrot static int nintendo_otp_reg_read(void *context, 493683b761SEmmanuel Gil Peyrot unsigned int reg, void *_val, size_t bytes) 503683b761SEmmanuel Gil Peyrot { 513683b761SEmmanuel Gil Peyrot struct nintendo_otp_priv *priv = context; 523683b761SEmmanuel Gil Peyrot u32 *val = _val; 533683b761SEmmanuel Gil Peyrot int words = bytes / WORD_SIZE; 543683b761SEmmanuel Gil Peyrot u32 bank, addr; 553683b761SEmmanuel Gil Peyrot 563683b761SEmmanuel Gil Peyrot while (words--) { 573683b761SEmmanuel Gil Peyrot bank = (reg / BANK_SIZE) << 8; 583683b761SEmmanuel Gil Peyrot addr = (reg / WORD_SIZE) % (BANK_SIZE / WORD_SIZE); 593683b761SEmmanuel Gil Peyrot iowrite32be(OTP_READ | bank | addr, priv->regs + HW_OTPCMD); 603683b761SEmmanuel Gil Peyrot *val++ = ioread32be(priv->regs + HW_OTPDATA); 613683b761SEmmanuel Gil Peyrot reg += WORD_SIZE; 623683b761SEmmanuel Gil Peyrot } 633683b761SEmmanuel Gil Peyrot 643683b761SEmmanuel Gil Peyrot return 0; 653683b761SEmmanuel Gil Peyrot } 663683b761SEmmanuel Gil Peyrot 673683b761SEmmanuel Gil Peyrot static const struct of_device_id nintendo_otp_of_table[] = { 683683b761SEmmanuel Gil Peyrot { .compatible = "nintendo,hollywood-otp", .data = &hollywood_otp_data }, 693683b761SEmmanuel Gil Peyrot { .compatible = "nintendo,latte-otp", .data = &latte_otp_data }, 703683b761SEmmanuel Gil Peyrot {/* sentinel */}, 713683b761SEmmanuel Gil Peyrot }; 723683b761SEmmanuel Gil Peyrot MODULE_DEVICE_TABLE(of, nintendo_otp_of_table); 733683b761SEmmanuel Gil Peyrot 743683b761SEmmanuel Gil Peyrot static int nintendo_otp_probe(struct platform_device *pdev) 753683b761SEmmanuel Gil Peyrot { 763683b761SEmmanuel Gil Peyrot struct device *dev = &pdev->dev; 773683b761SEmmanuel Gil Peyrot const struct of_device_id *of_id = 783683b761SEmmanuel Gil Peyrot of_match_device(nintendo_otp_of_table, dev); 793683b761SEmmanuel Gil Peyrot struct nvmem_device *nvmem; 803683b761SEmmanuel Gil Peyrot struct nintendo_otp_priv *priv; 813683b761SEmmanuel Gil Peyrot 823683b761SEmmanuel Gil Peyrot struct nvmem_config config = { 833683b761SEmmanuel Gil Peyrot .stride = WORD_SIZE, 843683b761SEmmanuel Gil Peyrot .word_size = WORD_SIZE, 853683b761SEmmanuel Gil Peyrot .reg_read = nintendo_otp_reg_read, 863683b761SEmmanuel Gil Peyrot .read_only = true, 873683b761SEmmanuel Gil Peyrot .root_only = true, 883683b761SEmmanuel Gil Peyrot }; 893683b761SEmmanuel Gil Peyrot 903683b761SEmmanuel Gil Peyrot priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 913683b761SEmmanuel Gil Peyrot if (!priv) 923683b761SEmmanuel Gil Peyrot return -ENOMEM; 933683b761SEmmanuel Gil Peyrot 94*64940999SYang Li priv->regs = devm_platform_ioremap_resource(pdev, 0); 953683b761SEmmanuel Gil Peyrot if (IS_ERR(priv->regs)) 963683b761SEmmanuel Gil Peyrot return PTR_ERR(priv->regs); 973683b761SEmmanuel Gil Peyrot 983683b761SEmmanuel Gil Peyrot if (of_id->data) { 993683b761SEmmanuel Gil Peyrot const struct nintendo_otp_devtype_data *data = of_id->data; 1003683b761SEmmanuel Gil Peyrot config.name = data->name; 1013683b761SEmmanuel Gil Peyrot config.size = data->num_banks * BANK_SIZE; 1023683b761SEmmanuel Gil Peyrot } 1033683b761SEmmanuel Gil Peyrot 1043683b761SEmmanuel Gil Peyrot config.dev = dev; 1053683b761SEmmanuel Gil Peyrot config.priv = priv; 1063683b761SEmmanuel Gil Peyrot 1073683b761SEmmanuel Gil Peyrot nvmem = devm_nvmem_register(dev, &config); 1083683b761SEmmanuel Gil Peyrot 1093683b761SEmmanuel Gil Peyrot return PTR_ERR_OR_ZERO(nvmem); 1103683b761SEmmanuel Gil Peyrot } 1113683b761SEmmanuel Gil Peyrot 1123683b761SEmmanuel Gil Peyrot static struct platform_driver nintendo_otp_driver = { 1133683b761SEmmanuel Gil Peyrot .probe = nintendo_otp_probe, 1143683b761SEmmanuel Gil Peyrot .driver = { 1153683b761SEmmanuel Gil Peyrot .name = "nintendo-otp", 1163683b761SEmmanuel Gil Peyrot .of_match_table = nintendo_otp_of_table, 1173683b761SEmmanuel Gil Peyrot }, 1183683b761SEmmanuel Gil Peyrot }; 1193683b761SEmmanuel Gil Peyrot module_platform_driver(nintendo_otp_driver); 1203683b761SEmmanuel Gil Peyrot MODULE_AUTHOR("Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>"); 1213683b761SEmmanuel Gil Peyrot MODULE_DESCRIPTION("Nintendo Wii and Wii U OTP driver"); 1223683b761SEmmanuel Gil Peyrot MODULE_LICENSE("GPL v2"); 123