From patchwork Tue Nov 4 05:46:16 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhao Qiang X-Patchwork-Id: 406447 X-Patchwork-Delegate: yorksun@freescale.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 2CE6E14003E for ; Tue, 4 Nov 2014 16:47:42 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 258954B894; Tue, 4 Nov 2014 06:47:39 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 1m0yvyuet5Y1; Tue, 4 Nov 2014 06:47:38 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 790734B8B1; Tue, 4 Nov 2014 06:47:38 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id A4B224B8B1 for ; Tue, 4 Nov 2014 06:47:31 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id go25mBVQPWnR for ; Tue, 4 Nov 2014 06:47:31 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from na01-bn1-obe.outbound.protection.outlook.com (mail-bn1bon0114.outbound.protection.outlook.com [157.56.111.114]) by theia.denx.de (Postfix) with ESMTPS id 1E9FD4B894 for ; Tue, 4 Nov 2014 06:47:28 +0100 (CET) Received: from BN3PR0301CA0062.namprd03.prod.outlook.com (25.160.152.158) by DM2PR03MB350.namprd03.prod.outlook.com (10.141.54.21) with Microsoft SMTP Server (TLS) id 15.1.11.9; Tue, 4 Nov 2014 05:47:24 +0000 Received: from BN1BFFO11FD038.protection.gbl (2a01:111:f400:7c10::1:177) by BN3PR0301CA0062.outlook.office365.com (2a01:111:e400:401e::30) with Microsoft SMTP Server (TLS) id 15.1.16.15 via Frontend Transport; Tue, 4 Nov 2014 05:47:23 +0000 Received: from tx30smr01.am.freescale.net (192.88.168.50) by BN1BFFO11FD038.mail.protection.outlook.com (10.58.144.101) with Microsoft SMTP Server (TLS) id 15.1.6.13 via Frontend Transport; Tue, 4 Nov 2014 05:47:23 +0000 Received: from titan.ap.freescale.net ([10.192.208.233]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id sA45lALf008965; Mon, 3 Nov 2014 22:47:21 -0700 From: Zhao Qiang To: , Date: Tue, 4 Nov 2014 13:46:16 +0800 Message-ID: <1415079976-48022-1-git-send-email-B45475@freescale.com> X-Mailer: git-send-email 2.1.0.27.g96db324 X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:192.88.168.50; CTRY:US; IPV:CAL; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(10019020)(6009001)(189002)(199003)(87286001)(26826002)(64706001)(84676001)(47776003)(50466002)(48376002)(89996001)(104166001)(104016003)(77156002)(87936001)(50986999)(97736003)(102836001)(31966008)(50226001)(4396001)(20776003)(92726001)(68736004)(93916002)(19580405001)(6806004)(44976005)(99396003)(229853001)(21056001)(19580395003)(450100001)(88136002)(92566001)(46102003)(95666004)(105606002)(120916001)(36756003)(106466001)(107046002)(62966003)(42262002); DIR:OUT; SFP:1102; SCL:1; SRVR:DM2PR03MB350; H:tx30smr01.am.freescale.net; FPR:; MLV:ovrnspm; PTR:InfoDomainNonexistent; MX:1; A:1; LANG:en; MIME-Version: 1.0 X-Microsoft-Antispam: UriScan:; X-Microsoft-Antispam: BCL:0;PCL:0;RULEID:;SRVR:DM2PR03MB350; X-Forefront-PRVS: 03853D523D Received-SPF: Fail (protection.outlook.com: domain of freescale.com does not designate 192.88.168.50 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.168.50; helo=tx30smr01.am.freescale.net; Authentication-Results: spf=fail (sender IP is 192.88.168.50) smtp.mailfrom=qiang.zhao@freescale.com; X-OriginatorOrg: freescale.com Cc: Zhao Qiang Subject: [U-Boot] [PATCH v2] u_qe: add u_qe_upload_firmware for u_qe X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.13 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de Signed-off-by: Zhao Qiang --- Changes for v2: - put u_qe functions under "#ifdef CONFIG_U_QE" drivers/qe/qe.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- drivers/qe/qe.h | 6 ++- 2 files changed, 133 insertions(+), 2 deletions(-) diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c index 4de1881..bc94673 100644 --- a/drivers/qe/qe.c +++ b/drivers/qe/qe.c @@ -182,14 +182,16 @@ void qe_init(uint qe_base) qe_snums_init(); } +#ifdef CONFIG_U_QE void u_qe_init(void) { uint qe_base = CONFIG_SYS_IMMR + 0x01400000; /* QE immr base */ qe_immr = (qe_map_t *)qe_base; - qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR); + u_qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR); out_be32(&qe_immr->iram.iready, QE_IRAM_READY); } +#endif void qe_reset(void) { @@ -442,6 +444,131 @@ int qe_upload_firmware(const struct qe_firmware *firmware) return 0; } +#ifdef CONFIG_U_QE +/* + * Upload a microcode to the I-RAM at a specific address. + * + * See docs/README.qe_firmware for information on QE microcode uploading. + * + * Currently, only version 1 is supported, so the 'version' field must be + * set to 1. + * + * The SOC model and revision are not validated, they are only displayed for + * informational purposes. + * + * 'calc_size' is the calculated size, in bytes, of the firmware structure and + * all of the microcode structures, minus the CRC. + * + * 'length' is the size that the structure says it is, including the CRC. + */ +int u_qe_upload_firmware(const struct qe_firmware *firmware) +{ + unsigned int i; + unsigned int j; + u32 crc; + size_t calc_size = sizeof(struct qe_firmware); + size_t length; + const struct qe_header *hdr; +#ifdef CONFIG_DEEP_SLEEP + ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); +#endif + if (!firmware) { + printf("Invalid address\n"); + return -EINVAL; + } + + hdr = &firmware->header; + length = be32_to_cpu(hdr->length); + + /* Check the magic */ + if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || + (hdr->magic[2] != 'F')) { + printf("Not a microcode\n"); +#ifdef CONFIG_DEEP_SLEEP + setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE); +#endif + return -EPERM; + } + + /* Check the version */ + if (hdr->version != 1) { + printf("Unsupported version\n"); + return -EPERM; + } + + /* Validate some of the fields */ + if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) { + printf("Invalid data\n"); + return -EINVAL; + } + + /* Validate the length and check if there's a CRC */ + calc_size += (firmware->count - 1) * sizeof(struct qe_microcode); + + for (i = 0; i < firmware->count; i++) + /* + * For situations where the second RISC uses the same microcode + * as the first, the 'code_offset' and 'count' fields will be + * zero, so it's okay to add those. + */ + calc_size += sizeof(u32) * + be32_to_cpu(firmware->microcode[i].count); + + /* Validate the length */ + if (length != calc_size + sizeof(u32)) { + printf("Invalid length\n"); + return -EPERM; + } + + /* + * Validate the CRC. We would normally call crc32_no_comp(), but that + * function isn't available unless you turn on JFFS support. + */ + crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size)); + if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) { + printf("Firmware CRC is invalid\n"); + return -EIO; + } + + /* + * If the microcode calls for it, split the I-RAM. + */ + if (!firmware->split) { + out_be16(&qe_immr->cp.cercr, + in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR); + } + + if (firmware->soc.model) + printf("Firmware '%s' for %u V%u.%u\n", + firmware->id, be16_to_cpu(firmware->soc.model), + firmware->soc.major, firmware->soc.minor); + else + printf("Firmware '%s'\n", firmware->id); + + /* Loop through each microcode. */ + for (i = 0; i < firmware->count; i++) { + const struct qe_microcode *ucode = &firmware->microcode[i]; + + /* Upload a microcode if it's present */ + if (ucode->code_offset) + qe_upload_microcode(firmware, ucode); + + /* Program the traps for this processor */ + for (j = 0; j < 16; j++) { + u32 trap = be32_to_cpu(ucode->traps[j]); + + if (trap) + out_be32(&qe_immr->rsp[i].tibcr[j], trap); + } + + /* Enable traps */ + out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr)); + } + + return 0; +} +#endif + struct qe_firmware_info *qe_get_firmware_info(void) { return qe_firmware_uploaded ? &qe_firmware_info : NULL; diff --git a/drivers/qe/qe.h b/drivers/qe/qe.h index 30484b8..33878f8 100644 --- a/drivers/qe/qe.h +++ b/drivers/qe/qe.h @@ -275,7 +275,6 @@ void *qe_muram_addr(uint offset); int qe_get_snum(void); void qe_put_snum(u8 snum); void qe_init(uint qe_base); -void u_qe_init(void); void qe_reset(void); void qe_assign_page(uint snum, uint para_ram_base); int qe_set_brg(uint brg, uint rate); @@ -286,4 +285,9 @@ void ft_qe_setup(void *blob); void qe_init(uint qe_base); void qe_reset(void); +#ifdef CONFIG_U_QE +void u_qe_init(void); +int u_qe_upload_firmware(const struct qe_firmware *firmware); +#endif + #endif /* __QE_H__ */