1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * QTI hardware key manager driver.
- *
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
- */
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/mod_devicetable.h>
- #include <linux/device.h>
- #include <linux/clk.h>
- #include <linux/err.h>
- #include <linux/dma-mapping.h>
- #include <linux/io.h>
- #include <linux/platform_device.h>
- #include <linux/spinlock.h>
- #include <linux/delay.h>
- #include <linux/crypto.h>
- #include <linux/bitops.h>
- #include <linux/iommu.h>
- #include <linux/hwkm.h>
- #include "hwkmregs.h"
- #include "hwkm_serialize.h"
- #define BYTES_TO_WORDS(bytes) (((bytes) + 3) / 4)
- #define WRITE_TO_KDF_PACKET(cmd_ptr, src, len) \
- do { \
- memcpy(cmd_ptr, src, len); \
- cmd_ptr += len; \
- } while (0)
- #define ASYNC_CMD_HANDLING false
- /* Maximum number of times to poll */
- #define MAX_RETRIES 20000
- int retries;
- #define WAIT_UNTIL(cond) \
- for (retries = 0; !(cond) && (retries < MAX_RETRIES); retries++)
- #define EXPECTED_UNWRAP_KEY_SIZE 68
- #define ICEMEM_SLAVE_TPKEY_VAL 0x192
- #define KM_MASTER_TPKEY_SLOT 10
- #define BYTE_ORDER_VAL 8
- #define qti_hwkm_readl(hwkm, reg, dest) \
- (((dest) == KM_MASTER) ? \
- (readl_relaxed((void __iomem *)((hwkm)->km_base + (reg)))) : \
- (readl_relaxed((void __iomem *)((hwkm)->ice_hwkm_mmio + (reg)))))
- #define qti_hwkm_writel(hwkm, val, reg, dest) \
- (((dest) == KM_MASTER) ? \
- (writel_relaxed((val), (void __iomem *)((hwkm)->km_base + (reg)))) :\
- (writel_relaxed((val), (void __iomem *)((hwkm)->ice_hwkm_mmio + (reg)))))
- #define qti_hwkm_setb(hwkm, reg, nr, dest) { \
- u32 val = qti_hwkm_readl(hwkm, reg, dest); \
- val |= (0x1 << nr); \
- qti_hwkm_writel(hwkm, val, reg, dest); \
- }
- #define qti_hwkm_clearb(hwkm, reg, nr, dest) { \
- u32 val = qti_hwkm_readl(hwkm, reg, dest); \
- val &= ~(0x1 << nr); \
- qti_hwkm_writel(hwkm, val, reg, dest); \
- }
- struct hwkm_clk_info {
- struct list_head list;
- struct clk *clk;
- const char *name;
- u32 max_freq;
- u32 min_freq;
- u32 curr_freq;
- bool enabled;
- };
- static struct ice_mmio_data *mmio_data_ref;
- static unsigned int qti_hwkm_get_reg_data(struct ice_mmio_data *mmio_data,
- u32 reg, u32 offset, u32 mask,
- enum hwkm_destination dest)
- {
- u32 val;
- val = qti_hwkm_readl(mmio_data, reg, dest);
- return ((val & mask) >> offset);
- }
- static bool qti_hwkm_testb(struct ice_mmio_data *mmio_data, u32 reg, u8 nr,
- enum hwkm_destination dest)
- {
- u32 val = qti_hwkm_readl(mmio_data, reg, dest);
- val = (val >> nr) & 0x1;
- if (val == 0)
- return false;
- return true;
- }
- /**
- * qti_hwkm_master_transaction() - Send a command packet to the HWKM Master instance.
- *
- * @mmio_data: Structure holding ICE address registers.
- * @cmd_packet: Pointer to Master transaction command.
- * @cmd_words: Master transaction command size.
- * @rsp_packet: Pointer to Master transaction response.
- * @rsp_words: Master transaction response size.
- *
- * in section 3.2.5.1 of Key Manager HPG
- * - Clear CMD FIFO
- * - Clear Error Status Register
- * - Write CMD_ENABLE = 1
- * - for word in cmd_packet:
- * - poll until CMD_FIFO_AVAILABLE_SPACE > 0.
- * Timeout error after 1,000 retries.
- * - write word to CMD register
- * - for word in rsp_packet:
- * - poll until RSP_FIFO_AVAILABLE_DATA > 0.
- * Timeout error after 1,000 retries.
- * - read word from RSP register
- * - Verify CMD_DONE == 1
- * - Clear CMD_DONE
- *
- * Context: Any context.
- *
- * Return: Return 0 if success, -EINVAL on failure.
- */
- static int qti_hwkm_master_transaction(struct ice_mmio_data *mmio_data,
- const uint32_t *cmd_packet,
- size_t cmd_words,
- uint32_t *rsp_packet,
- size_t rsp_words)
- {
- int i;
- u32 val;
- uint32_t rsp_discard;
- /* Clear CMD FIFO */
- qti_hwkm_setb(mmio_data_ref, QTI_HWKM_MASTER_RG_BANK2_BANKN_CTL,
- CMD_FIFO_CLEAR_BIT, KM_MASTER);
- /* Write memory barrier */
- wmb();
- qti_hwkm_clearb(mmio_data_ref, QTI_HWKM_MASTER_RG_BANK2_BANKN_CTL,
- CMD_FIFO_CLEAR_BIT, KM_MASTER);
- /* Write memory barrier */
- wmb();
- /* Clear previous CMD errors, write 1 to err bits */
- val = qti_hwkm_readl(mmio_data_ref, QTI_HWKM_MASTER_RG_BANK2_BANKN_ESR,
- KM_MASTER);
- qti_hwkm_writel(mmio_data_ref, val,
- QTI_HWKM_MASTER_RG_BANK2_BANKN_ESR,
- KM_MASTER);
- /* Write memory barrier */
- wmb();
- /* Enable command */
- qti_hwkm_setb(mmio_data_ref, QTI_HWKM_MASTER_RG_BANK2_BANKN_CTL, CMD_ENABLE_BIT,
- KM_MASTER);
- /* Write memory barrier */
- wmb();
- if (qti_hwkm_testb(mmio_data_ref, QTI_HWKM_MASTER_RG_BANK2_BANKN_CTL,
- CMD_FIFO_CLEAR_BIT, KM_MASTER)) {
- pr_err("%s: CMD_FIFO_CLEAR_BIT not set\n", __func__);
- return -1;
- }
- if (qti_hwkm_testb(mmio_data_ref, QTI_HWKM_MASTER_RG_BANK2_BANKN_IRQ_STATUS,
- RSP_FIFO_NOT_EMPTY, KM_MASTER)) {
- while (qti_hwkm_get_reg_data(mmio_data_ref,
- QTI_HWKM_MASTER_RG_BANK2_BANKN_STATUS,
- RSP_FIFO_AVAILABLE_DATA, RSP_FIFO_AVAILABLE_DATA_MASK,
- KM_MASTER) > 0) {
- rsp_discard = qti_hwkm_readl(mmio_data_ref,
- QTI_HWKM_MASTER_RG_BANK2_RSP_0, KM_MASTER);
- }
- /* Clear RSP_FIFO_NOT_EMPTY status bit */
- qti_hwkm_setb(mmio_data_ref, QTI_HWKM_MASTER_RG_BANK2_BANKN_IRQ_STATUS,
- RSP_FIFO_NOT_EMPTY, KM_MASTER);
- /* Write memory barrier */
- wmb();
- }
- for (i = 0; i < cmd_words; i++) {
- WAIT_UNTIL(qti_hwkm_get_reg_data(mmio_data_ref,
- QTI_HWKM_MASTER_RG_BANK2_BANKN_STATUS,
- CMD_FIFO_AVAILABLE_SPACE, CMD_FIFO_AVAILABLE_SPACE_MASK,
- KM_MASTER) > 0);
- if (qti_hwkm_get_reg_data(mmio_data_ref,
- QTI_HWKM_MASTER_RG_BANK2_BANKN_STATUS,
- CMD_FIFO_AVAILABLE_SPACE, CMD_FIFO_AVAILABLE_SPACE_MASK,
- KM_MASTER) == 0) {
- pr_err("%s: cmd fifo space not available\n", __func__);
- return -1;
- }
- qti_hwkm_writel(mmio_data_ref, cmd_packet[i],
- QTI_HWKM_MASTER_RG_BANK2_CMD_0, KM_MASTER);
- /* Write memory barrier */
- wmb();
- }
- for (i = 0; i < rsp_words; i++) {
- WAIT_UNTIL(qti_hwkm_get_reg_data(mmio_data_ref,
- QTI_HWKM_MASTER_RG_BANK2_BANKN_STATUS,
- RSP_FIFO_AVAILABLE_DATA, RSP_FIFO_AVAILABLE_DATA_MASK,
- KM_MASTER) > 0);
- if (qti_hwkm_get_reg_data(mmio_data_ref,
- QTI_HWKM_MASTER_RG_BANK2_BANKN_STATUS,
- RSP_FIFO_AVAILABLE_DATA, RSP_FIFO_AVAILABLE_DATA_MASK,
- KM_MASTER) == 0) {
- pr_err("%s: rsp fifo data not available\n", __func__);
- return -EINVAL;
- }
- rsp_packet[i] = qti_hwkm_readl(mmio_data_ref,
- QTI_HWKM_MASTER_RG_BANK2_RSP_0, KM_MASTER);
- }
- if (!qti_hwkm_testb(mmio_data_ref, QTI_HWKM_MASTER_RG_BANK2_BANKN_IRQ_STATUS,
- CMD_DONE_BIT, KM_MASTER)) {
- pr_err("%s: CMD_DONE_BIT not set\n", __func__);
- return -1;
- }
- /* Clear CMD_DONE status bit */
- qti_hwkm_setb(mmio_data_ref, QTI_HWKM_MASTER_RG_BANK2_BANKN_IRQ_STATUS,
- CMD_DONE_BIT, KM_MASTER);
- /* Write memory barrier */
- wmb();
- return 0;
- }
- /**
- * qti_hwkm_ice_transaction(): Process ICE Slave transactions.
- *
- * @mmio_data: Structure holding ICE address registers.
- * @cmd_packet: Pointer to Master transaction command.
- * @cmd_words: Master transaction command size.
- * @rsp_packet: Pointer to Master transaction response.
- * @rsp_words: Master transaction response size.
- *
- * Send a command packet to the HWKM ICE slave instance as described in
- * section 3.2.5.1 of Key Manager HPG
- * - Clear CMD FIFO
- * - Clear Error Status Register
- * - Write CMD_ENABLE = 1
- * - for word in cmd_packet:
- * - poll until CMD_FIFO_AVAILABLE_SPACE > 0.
- * Timeout error after 1,000 retries.
- * - write word to CMD register
- * - for word in rsp_packet:
- * - poll until RSP_FIFO_AVAILABLE_DATA > 0.
- * Timeout error after 1,000 retries.
- * - read word from RSP register
- * - Verify CMD_DONE == 1
- * - Clear CMD_DONE
- *
- * Context: Any context.
- *
- * Return: Return 0 if success, -1 on failure.
- */
- static int qti_hwkm_ice_transaction(struct ice_mmio_data *mmio_data,
- const uint32_t *cmd_packet,
- size_t cmd_words,
- uint32_t *rsp_packet,
- size_t rsp_words)
- {
- int i;
- u32 val;
- uint32_t rsp_discard;
- /* Clear CMD FIFO */
- qti_hwkm_setb(mmio_data, QTI_HWKM_ICE_RG_BANK0_BANKN_CTL,
- CMD_FIFO_CLEAR_BIT, ICEMEM_SLAVE);
- /* Write memory barrier */
- wmb();
- qti_hwkm_clearb(mmio_data, QTI_HWKM_ICE_RG_BANK0_BANKN_CTL,
- CMD_FIFO_CLEAR_BIT, ICEMEM_SLAVE);
- /* Write memory barrier */
- wmb();
- /* Clear previous CMD errors, write 1 to err bits */
- val = qti_hwkm_readl(mmio_data, QTI_HWKM_ICE_RG_BANK0_BANKN_ESR,
- ICEMEM_SLAVE);
- qti_hwkm_writel(mmio_data, val,
- QTI_HWKM_ICE_RG_BANK0_BANKN_ESR,
- ICEMEM_SLAVE);
- /* Write memory barrier */
- wmb();
- /* Enable command */
- qti_hwkm_setb(mmio_data, QTI_HWKM_ICE_RG_BANK0_BANKN_CTL, CMD_ENABLE_BIT,
- ICEMEM_SLAVE);
- /* Write memory barrier */
- wmb();
- if (qti_hwkm_testb(mmio_data, QTI_HWKM_ICE_RG_BANK0_BANKN_CTL,
- CMD_FIFO_CLEAR_BIT, ICEMEM_SLAVE)) {
- pr_err("%s: CMD_FIFO_CLEAR_BIT not set\n", __func__);
- return -1;
- }
- if (qti_hwkm_testb(mmio_data, QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_STATUS,
- RSP_FIFO_NOT_EMPTY, ICEMEM_SLAVE)) {
- while (qti_hwkm_get_reg_data(mmio_data,
- QTI_HWKM_ICE_RG_BANK0_BANKN_STATUS,
- RSP_FIFO_AVAILABLE_DATA, RSP_FIFO_AVAILABLE_DATA_MASK,
- ICEMEM_SLAVE) > 0) {
- rsp_discard = qti_hwkm_readl(mmio_data,
- QTI_HWKM_ICE_RG_BANK0_RSP_0, ICEMEM_SLAVE);
- }
- pr_err("%s: while exit\n", __func__);
- /* Clear RSP_FIFO_NOT_EMPTY status bit */
- qti_hwkm_setb(mmio_data, QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_STATUS,
- RSP_FIFO_NOT_EMPTY, ICEMEM_SLAVE);
- /* Write memory barrier */
- wmb();
- }
- for (i = 0; i < cmd_words; i++) {
- WAIT_UNTIL(qti_hwkm_get_reg_data(mmio_data,
- QTI_HWKM_ICE_RG_BANK0_BANKN_STATUS,
- CMD_FIFO_AVAILABLE_SPACE, CMD_FIFO_AVAILABLE_SPACE_MASK,
- ICEMEM_SLAVE) > 0);
- if (qti_hwkm_get_reg_data(mmio_data,
- QTI_HWKM_ICE_RG_BANK0_BANKN_STATUS,
- CMD_FIFO_AVAILABLE_SPACE, CMD_FIFO_AVAILABLE_SPACE_MASK,
- ICEMEM_SLAVE) == 0) {
- pr_err("%s: cmd fifo space not available\n", __func__);
- return -1;
- }
- qti_hwkm_writel(mmio_data, cmd_packet[i],
- QTI_HWKM_ICE_RG_BANK0_CMD_0, ICEMEM_SLAVE);
- /* Write memory barrier */
- wmb();
- }
- for (i = 0; i < rsp_words; i++) {
- WAIT_UNTIL(qti_hwkm_get_reg_data(mmio_data,
- QTI_HWKM_ICE_RG_BANK0_BANKN_STATUS,
- RSP_FIFO_AVAILABLE_DATA, RSP_FIFO_AVAILABLE_DATA_MASK,
- ICEMEM_SLAVE) > 0);
- if (qti_hwkm_get_reg_data(mmio_data,
- QTI_HWKM_ICE_RG_BANK0_BANKN_STATUS,
- RSP_FIFO_AVAILABLE_DATA, RSP_FIFO_AVAILABLE_DATA_MASK,
- ICEMEM_SLAVE) == 0) {
- pr_err("%s: rsp fifo data not available\n", __func__);
- return -1;
- }
- rsp_packet[i] = qti_hwkm_readl(mmio_data,
- QTI_HWKM_ICE_RG_BANK0_RSP_0, ICEMEM_SLAVE);
- }
- if (!qti_hwkm_testb(mmio_data, QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_STATUS,
- CMD_DONE_BIT, ICEMEM_SLAVE)) {
- pr_err("%s: CMD_DONE_BIT not set\n", __func__);
- return -1;
- }
- /* Clear CMD_DONE status bit */
- qti_hwkm_setb(mmio_data, QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_STATUS,
- CMD_DONE_BIT, ICEMEM_SLAVE);
- /* Write memory barrier */
- wmb();
- return 0;
- }
- /*
- * qti_hwkm_run_transaction() - Send a command packet to the selected KM instance and read
- * the response
- *
- * @mmio_data [in] Structure holding ICE address registers.
- * @dest [in] Destination KM instance.
- * @cmd_packet [in] pointer to start of command packet.
- * @cmd_words [in] words in the command packet.
- * @rsp_packet [out] pointer to start of response packet.
- * @rsp_words [in] words in the response buffer.
- *
- * Context: Any context.
- *
- * Return: Return 0 if success, -EINVAL on failure. -2 for Default.
- */
- static int qti_hwkm_run_transaction(struct ice_mmio_data *mmio_data,
- enum hwkm_destination dest,
- const uint32_t *cmd_packet,
- size_t cmd_words,
- uint32_t *rsp_packet,
- size_t rsp_words)
- {
- int status;
- if (cmd_packet == NULL || rsp_packet == NULL) {
- status = -EINVAL;
- return status;
- }
- switch (dest) {
- case KM_MASTER:
- status = qti_hwkm_master_transaction(mmio_data,
- cmd_packet, cmd_words,
- rsp_packet, rsp_words);
- break;
- case ICEMEM_SLAVE:
- status = qti_hwkm_ice_transaction(mmio_data,
- cmd_packet, cmd_words,
- rsp_packet, rsp_words);
- break;
- default:
- status = -2;
- break;
- }
- return status;
- }
- static void serialize_policy(struct hwkm_serialized_policy *out,
- const struct hwkm_key_policy *policy)
- {
- memset(out, 0, sizeof(struct hwkm_serialized_policy));
- out->wrap_with_tpkey = policy->wrap_with_tpk_allowed;
- out->hw_destination = policy->hw_destination;
- out->security_level = policy->security_lvl;
- out->swap_export_allowed = policy->swap_export_allowed;
- out->wrap_export_allowed = policy->wrap_export_allowed;
- out->key_type = policy->key_type;
- out->kdf_depth = policy->kdf_depth;
- out->encrypt_allowed = policy->enc_allowed;
- out->decrypt_allowed = policy->dec_allowed;
- out->alg_allowed = policy->alg_allowed;
- out->key_management_by_tz_secure_allowed = policy->km_by_tz_allowed;
- out->key_management_by_nonsecure_allowed = policy->km_by_nsec_allowed;
- out->key_management_by_modem_allowed = policy->km_by_modem_allowed;
- out->key_management_by_spu_allowed = policy->km_by_spu_allowed;
- }
- static void serialize_kdf_bsve(struct hwkm_kdf_bsve *out,
- const struct hwkm_bsve *bsve, u8 mks)
- {
- memset(out, 0, sizeof(struct hwkm_kdf_bsve));
- out->mks = mks;
- out->key_policy_version_en = bsve->km_key_policy_ver_en;
- out->apps_secure_en = bsve->km_apps_secure_en;
- out->msa_secure_en = bsve->km_msa_secure_en;
- out->lcm_fuse_row_en = bsve->km_lcm_fuse_en;
- out->boot_stage_otp_en = bsve->km_boot_stage_otp_en;
- out->swc_en = bsve->km_swc_en;
- out->fuse_region_sha_digest_en = bsve->km_fuse_region_sha_digest_en;
- out->child_key_policy_en = bsve->km_child_key_policy_en;
- out->mks_en = bsve->km_mks_en;
- }
- static void deserialize_policy(struct hwkm_key_policy *out,
- const struct hwkm_serialized_policy *policy)
- {
- memset(out, 0, sizeof(struct hwkm_key_policy));
- out->wrap_with_tpk_allowed = policy->wrap_with_tpkey;
- out->hw_destination = policy->hw_destination;
- out->security_lvl = policy->security_level;
- out->swap_export_allowed = policy->swap_export_allowed;
- out->wrap_export_allowed = policy->wrap_export_allowed;
- out->key_type = policy->key_type;
- out->kdf_depth = policy->kdf_depth;
- out->enc_allowed = policy->encrypt_allowed;
- out->dec_allowed = policy->decrypt_allowed;
- out->alg_allowed = policy->alg_allowed;
- out->km_by_tz_allowed = policy->key_management_by_tz_secure_allowed;
- out->km_by_nsec_allowed = policy->key_management_by_nonsecure_allowed;
- out->km_by_modem_allowed = policy->key_management_by_modem_allowed;
- out->km_by_spu_allowed = policy->key_management_by_spu_allowed;
- }
- static void reverse_bytes(u8 *bytes, size_t len)
- {
- size_t left;
- size_t right;
- for (left = 0, right = len - 1; left < right; left++, right--) {
- bytes[left] ^= bytes[right];
- bytes[right] ^= bytes[left];
- bytes[left] ^= bytes[right];
- }
- }
- static void reorder_ctx(u8 *ctx, size_t ctxlen)
- {
- int i;
- int len;
- len = ctxlen / BYTE_ORDER_VAL;
- /* Reverse ctx at 8 byte boundary */
- for (i = 0; i < len; i++)
- reverse_bytes(ctx + i*BYTE_ORDER_VAL, BYTE_ORDER_VAL);
- /*
- * If context is not a multiple of 8 bytes, reverse the last bytes
- * only. This simulates prepending the last 8 bytes with zeroes,
- * and then reversing the 8 bytes.
- */
- if (ctxlen % BYTE_ORDER_VAL != 0) {
- reverse_bytes(ctx + len*BYTE_ORDER_VAL,
- ctxlen % BYTE_ORDER_VAL);
- }
- }
- /*
- * qti_handle_key_unwrap_import() - Process Unwrap Import commad.
- *
- * @mmio_data: Structure holding ICE address registers.
- * @cmd_in: Pointer to input commnad packet.
- * @rsp_in: Pointer to output response packet.
- *
- * Command packet format (word indices):
- * CMD[0] = Operation info (OP, IRQ_EN, DKS, LEN)
- * CMD[1:17] = Wrapped Key Blob
- * CMD[18] = CRC (disabled)
- *
- * Response packet format (word indices):
- * RSP[0] = Operation info (OP, IRQ_EN, LEN)
- * RSP[1] = Error status
- *
- * Context: Any context.
- *
- * Return: Return 0 if success, -EINVAL on failure.
- */
- static int qti_handle_key_unwrap_import(struct ice_mmio_data *mmio_data,
- const struct hwkm_cmd *cmd_in,
- struct hwkm_rsp *rsp_in)
- {
- int status;
- u32 cmd[UNWRAP_IMPORT_CMD_WORDS] = {0};
- u32 rsp[UNWRAP_IMPORT_RSP_WORDS] = {0};
- struct hwkm_operation_info operation = {
- .op = KEY_UNWRAP_IMPORT,
- .irq_en = ASYNC_CMD_HANDLING,
- .slot1_desc = cmd_in->unwrap.dks,
- .slot2_desc = cmd_in->unwrap.kwk,
- .len = UNWRAP_IMPORT_CMD_WORDS
- };
- pr_debug("%s: KEY_UNWRAP_IMPORT start\n", __func__);
- if (cmd_in->unwrap.sz != EXPECTED_UNWRAP_KEY_SIZE) {
- pr_err("%s: Invalid key size - %d\n", __func__,
- cmd_in->unwrap.sz);
- return -EINVAL;
- }
- /*
- * Unwrap in HWKM does not do an integrity check for the last byte
- * (68th byte) as it is a noop. However, we need to make sure no
- * part of the keyblob provided was tampered with, even though it
- * is a noop. Adding an explicit check for the last byte before
- * providing to unwrap command.
- */
- if ((cmd_in->unwrap.wkb[EXPECTED_UNWRAP_KEY_SIZE - 1]) != 0x00) {
- pr_err("%s: Last byte corrupted, expecting zero value\n",
- __func__);
- return -EINVAL;
- }
- memcpy(cmd, &operation, OPERATION_INFO_LENGTH);
- memcpy(cmd + COMMAND_WRAPPED_KEY_IDX, cmd_in->unwrap.wkb,
- cmd_in->unwrap.sz);
- status = qti_hwkm_run_transaction(mmio_data, ICEMEM_SLAVE, cmd,
- UNWRAP_IMPORT_CMD_WORDS, rsp, UNWRAP_IMPORT_RSP_WORDS);
- if (status) {
- pr_err("%s: Error running transaction %d\n", __func__, status);
- return status;
- }
- rsp_in->status = rsp[RESPONSE_ERR_IDX];
- if (rsp_in->status) {
- pr_err("%s: KEY_UNWRAP_IMPORT error status 0x%x\n", __func__,
- rsp_in->status);
- return rsp_in->status;
- }
- return status;
- }
- /*
- * qti_handle_keyslot_clear() - Clear ICE slave keyslot.
- *
- * @mmio_data: Structure holding ICE address registers.
- * @cmd_in: Pointer to input commnad packet.
- * @rsp_in: Pointer to output response packet.
- *
- * Command packet format (word indices):
- * CMD[0] = Operation info (OP, IRQ_EN, DKS, DK, LEN)
- * CMD[1] = CRC (disabled)
- *
- * Response packet format (word indices):
- * RSP[0] = Operation info (OP, IRQ_EN, LEN)
- * RSP[1] = Error status
- *
- * Context: Any context.
- *
- * Return: Return: Return 0 if success, -EINVAL on failure.
- */
- static int qti_handle_keyslot_clear(struct ice_mmio_data *mmio_data, const struct hwkm_cmd *cmd_in,
- struct hwkm_rsp *rsp_in)
- {
- int status;
- u32 cmd[KEYSLOT_CLEAR_CMD_WORDS] = {0};
- u32 rsp[KEYSLOT_CLEAR_RSP_WORDS] = {0};
- struct hwkm_operation_info operation = {
- .op = KEY_SLOT_CLEAR,
- .irq_en = ASYNC_CMD_HANDLING,
- .slot1_desc = cmd_in->clear.dks,
- .op_flag = cmd_in->clear.is_double_key,
- .len = KEYSLOT_CLEAR_CMD_WORDS
- };
- pr_debug("%s: KEY_SLOT_CLEAR start\n", __func__);
- memcpy(cmd, &operation, OPERATION_INFO_LENGTH);
- status = qti_hwkm_run_transaction(mmio_data, ICEMEM_SLAVE, cmd,
- KEYSLOT_CLEAR_CMD_WORDS, rsp,
- KEYSLOT_CLEAR_RSP_WORDS);
- if (status) {
- pr_err("%s: Error running transaction %d\n", __func__, status);
- return status;
- }
- rsp_in->status = rsp[RESPONSE_ERR_IDX];
- if (rsp_in->status)
- return rsp_in->status;
- return status;
- }
- /*
- * qti_handle_system_kdf(): Process key derivation function.
- *
- * @mmio_data: Structure holding ICE address registers.
- * @cmd_in: Pointer to input commnad packet.
- * @rsp_in: Pointer to output response packet.
- *
- * NOTE: The command packet can vary in length. If BE = 0, the last 2 indices
- * for the BSVE are skipped. Similarly, if Software Context Length (SCL) < 16,
- * only SCL words are written to the packet. The CRC word is after the last
- * word of the SWC. The LEN field of this command does not include the SCL
- * (unlike other commands where the LEN field is the length of the entire
- * packet). The HW will expect SCL + LEN words to be sent.
- *
- * Command packet format (word indices):
- * CMD[0] = Operation info (OP, IRQ_EN, DKS, KDK, BE, SCL, LEN)
- * CMD[1:2] = Policy
- * CMD[3] = BSVE[0] if BE = 1, 0 if BE = 0
- * CMD[4:5] = BSVE[1:2] if BE = 1, skipped if BE = 0
- * CMD[6:21] = Software Context, only writing the number of words in SCL
- * CMD[22] = CRC
- *
- * Response packet format (word indices):
- * RSP[0] = Operation info (OP, IRQ_EN, LEN)
- * RSP[1] = Error status
- *
- * Context: Any context.
- *
- * Return: Return 0 if success, -EINVAL on failure.
- */
- static int qti_handle_system_kdf(struct ice_mmio_data *mmio_data, const struct hwkm_cmd *cmd_in,
- struct hwkm_rsp *rsp_in)
- {
- int status;
- u32 cmd[SYSTEM_KDF_CMD_MAX_WORDS] = {0};
- u32 rsp[SYSTEM_KDF_RSP_WORDS] = {0};
- u8 *cmd_ptr = (u8 *) cmd;
- struct hwkm_serialized_policy policy;
- struct hwkm_operation_info operation = {
- .op = SYSTEM_KDF,
- .irq_en = ASYNC_CMD_HANDLING,
- .slot1_desc = cmd_in->kdf.dks,
- .slot2_desc = cmd_in->kdf.kdk,
- .op_flag = cmd_in->kdf.bsve.enabled,
- .context_len = BYTES_TO_WORDS(cmd_in->kdf.sz),
- .len = SYSTEM_KDF_CMD_MIN_WORDS +
- (cmd_in->kdf.bsve.enabled ? BSVE_WORDS : 1)
- };
- pr_debug("%s: SYSTEM_KDF start\n", __func__);
- serialize_policy(&policy, &cmd_in->kdf.policy);
- /*
- * If context is not a multiple of 8 bytes, but a multiple
- * of 4 bytes, add a zero word at the end, to have a context multiple
- * of 8 bytes. This is to facilitate the context reordering that will
- * happen later
- */
- if ((cmd_in->kdf.sz) % BYTE_ORDER_VAL == (BYTE_ORDER_VAL/2))
- operation.context_len += 1;
- WRITE_TO_KDF_PACKET(cmd_ptr, &operation, OPERATION_INFO_LENGTH);
- WRITE_TO_KDF_PACKET(cmd_ptr, &policy, KEY_POLICY_LENGTH);
- if (cmd_in->kdf.bsve.enabled) {
- struct hwkm_kdf_bsve bsve;
- serialize_kdf_bsve(&bsve, &cmd_in->kdf.bsve, cmd_in->kdf.mks);
- WRITE_TO_KDF_PACKET(cmd_ptr, &bsve, MAX_BSVE_LENGTH);
- } else {
- /* Skip 4 bytes to align to start of context. */
- cmd_ptr += 4 * (sizeof(u8));
- }
- /*
- * Reorder context to reverse context bytes at the 8 byte
- * boundary. This is because crypto lib reads at this
- * boundary when populating the AD.
- */
- reorder_ctx((u8 *) cmd_in->kdf.ctx, cmd_in->kdf.sz);
- WRITE_TO_KDF_PACKET(cmd_ptr, cmd_in->kdf.ctx, cmd_in->kdf.sz);
- status = qti_hwkm_run_transaction(mmio_data, ICEMEM_SLAVE, cmd,
- operation.len + operation.context_len,
- rsp, SYSTEM_KDF_RSP_WORDS);
- if (status) {
- pr_err("%s: Error running transaction %d\n", __func__, status);
- return status;
- }
- rsp_in->status = rsp[RESPONSE_ERR_IDX];
- if (rsp_in->status) {
- pr_err("%s: SYSTEM_KDF error status 0x%x\n", __func__,
- rsp_in->status);
- return rsp_in->status;
- }
- return status;
- }
- /*
- * qti_handle_set_tpkey() - Send TP Key to ICE slave.
- *
- * @mmio_data: Structure holding ICE address registers.
- * @cmd_in: Pointer to input commnad packet.
- * @rsp_in: Pointer to output response packet.
- *
- * Command packet format (word indices):
- * CMD[0] = Operation info (OP, IRQ_EN, SKS, LEN)
- * CMD[1] = CRC (disabled)
- *
- * Response packet format (word indices):
- * RSP[0] = Operation info (OP, IRQ_EN, LEN)
- * RSP[1] = Error status
- *
- * Context: Any context.
- *
- * Return: Return 0 if success, -EINVAL on failure.
- */
- static int qti_handle_set_tpkey(struct ice_mmio_data *mmio_data, const struct hwkm_cmd *cmd_in,
- struct hwkm_rsp *rsp_in)
- {
- int status;
- u32 cmd[SET_TPKEY_CMD_WORDS] = {0};
- u32 rsp[SET_TPKEY_RSP_WORDS] = {0};
- struct hwkm_operation_info operation = {
- .op = SET_TPKEY,
- .irq_en = ASYNC_CMD_HANDLING,
- .slot1_desc = cmd_in->set_tpkey.sks,
- .len = SET_TPKEY_CMD_WORDS
- };
- pr_debug("%s: SET_TPKEY start\n", __func__);
- memcpy(cmd, &operation, OPERATION_INFO_LENGTH);
- status = qti_hwkm_run_transaction(mmio_data, KM_MASTER, cmd,
- SET_TPKEY_CMD_WORDS, rsp, SET_TPKEY_RSP_WORDS);
- if (status) {
- pr_err("%s: Error running transaction %d\n", __func__, status);
- return status;
- }
- rsp_in->status = rsp[RESPONSE_ERR_IDX];
- if (rsp_in->status) {
- pr_err("%s: SET_TPKEY error status 0x%x\n", __func__,
- rsp_in->status);
- return rsp_in->status;
- }
- return status;
- }
- /**
- * qti_handle_keyslot_rdwr() - Process read-write command.
- *
- * @mmio_data: Structure holding ICE address registers.
- * @cmd_in: Pointer to input commnad packet.
- * @rsp_in: Pointer to output response packet.
- *
- * 254 * NOTE: To anyone maintaining or porting this code wondering why the key
- * is reversed in the command packet: the plaintext key value is expected by
- * the HW in reverse byte order.
- * See section 1.8.2.2 of the HWKM CPAS for more details
- * Mapping of key to CE key read order:
- * Key[255:224] -> CRYPTO0_CRYPTO_ENCR_KEY0
- * Key[223:192] -> CRYPTO0_CRYPTO_ENCR_KEY1
- * ...
- * Key[63:32] -> CRYPTO0_CRYPTO_ENCR_KEY6
- * Key[31:0] -> CRYPTO0_CRYPTO_ENCR_KEY7
- * In this notation Key[31:0] is the least significant word of the key
- * If the key length is less than 256 bits, the key is filled in from
- * higher index to lower
- * For example, for a 128 bit key, Key[255:128] would have the key,
- * Key[127:0] would be all 0
- * This means that CMD[3:6] is all 0, CMD[7:10] has the key value.
- *
- * Command packet format (word indices):
- * CMD[0] = Operation info (OP, IRQ_EN, DKS/SKS, WE, LEN)
- * CMD[1:2] = Policy (0 if we == 0)
- * CMD[3:10] = Write key value (0 if we == 0)
- * CMD[11] = CRC (disabled)
- *
- * Response packet format (word indices):
- * RSP[0] = Operation info (OP, IRQ_EN, LEN)
- * RSP[1] = Error status
- * RSP[2:3] = Policy (0 if we == 1)
- * RSP[4:11] = Read key value (0 if we == 1)
- *
- * Context: Any context.
- *
- * Return: Return: Return 0 if success, -EINVAL on failure.
- *
- **/
- static int qti_handle_keyslot_rdwr(struct ice_mmio_data *mmio_data, const struct hwkm_cmd *cmd_in,
- struct hwkm_rsp *rsp_in)
- {
- int status;
- u32 cmd[KEYSLOT_RDWR_CMD_WORDS] = {0};
- u32 rsp[KEYSLOT_RDWR_RSP_WORDS] = {0};
- struct hwkm_serialized_policy policy;
- struct hwkm_operation_info operation = {
- .op = KEY_SLOT_RDWR,
- .irq_en = ASYNC_CMD_HANDLING,
- .slot1_desc = cmd_in->rdwr.slot,
- .op_flag = cmd_in->rdwr.is_write,
- .len = KEYSLOT_RDWR_CMD_WORDS
- };
- pr_debug("%s: KEY_SLOT_RDWR start\n", __func__);
- memcpy(cmd, &operation, OPERATION_INFO_LENGTH);
- if (cmd_in->rdwr.is_write) {
- serialize_policy(&policy, &cmd_in->rdwr.policy);
- memcpy(cmd + COMMAND_KEY_POLICY_IDX, &policy,
- KEY_POLICY_LENGTH);
- memcpy(cmd + COMMAND_KEY_VALUE_IDX, cmd_in->rdwr.key,
- cmd_in->rdwr.sz);
- /* Need to reverse the key because the HW expects it in reverse byte order */
- reverse_bytes((u8 *) (cmd + COMMAND_KEY_VALUE_IDX),
- HWKM_MAX_KEY_SIZE);
- }
- status = qti_hwkm_run_transaction(mmio_data, ICEMEM_SLAVE, cmd,
- KEYSLOT_RDWR_CMD_WORDS, rsp, KEYSLOT_RDWR_RSP_WORDS);
- if (status) {
- pr_err("%s: Error running transaction %d\n", __func__, status);
- return status;
- }
- rsp_in->status = rsp[RESPONSE_ERR_IDX];
- if (rsp_in->status) {
- pr_err("%s: KEY_SLOT_RDWR error status 0x%x\n",
- __func__, rsp_in->status);
- return rsp_in->status;
- }
- if (!cmd_in->rdwr.is_write &&
- (rsp_in->status == 0)) {
- memcpy(&policy, rsp + RESPONSE_KEY_POLICY_IDX,
- KEY_POLICY_LENGTH);
- memcpy(rsp_in->rdwr.key,
- rsp + RESPONSE_KEY_VALUE_IDX, RESPONSE_KEY_LENGTH);
- /* Need to reverse the key because the HW returns it in reverse byte order */
- reverse_bytes(rsp_in->rdwr.key, HWKM_MAX_KEY_SIZE);
- rsp_in->rdwr.sz = RESPONSE_KEY_LENGTH;
- deserialize_policy(&rsp_in->rdwr.policy, &policy);
- }
- /* Clear cmd and rsp buffers, since they may contain plaintext keys */
- memset(cmd, 0, sizeof(cmd));
- memset(rsp, 0, sizeof(rsp));
- return status;
- }
- static int qti_hwkm_parse_clock_info(struct platform_device *pdev,
- struct ice_mmio_data *hwkm_dev)
- {
- int ret = -EINVAL, cnt, i, len;
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- char *name;
- struct hwkm_clk_info *clki;
- u32 *clkfreq = NULL;
- if (!np)
- goto out;
- cnt = of_property_count_strings(np, "clock-names");
- if (cnt <= 0) {
- dev_info(dev, "%s: Unable to find clocks, assuming enabled\n",
- __func__);
- ret = cnt;
- goto out;
- }
- if (!of_get_property(np, "qcom,op-freq-hz", &len)) {
- dev_info(dev, "qcom,op-freq-hz property not specified\n");
- goto out;
- }
- len = len/sizeof(*clkfreq);
- if (len != cnt)
- goto out;
- clkfreq = devm_kzalloc(dev, len * sizeof(*clkfreq), GFP_KERNEL);
- if (!clkfreq) {
- ret = -ENOMEM;
- goto out;
- }
- ret = of_property_read_u32_array(np, "qcom,op-freq-hz", clkfreq, len);
- INIT_LIST_HEAD(&hwkm_dev->clk_list_head);
- for (i = 0; i < cnt; i++) {
- ret = of_property_read_string_index(np,
- "clock-names", i, (const char **)&name);
- if (ret)
- goto out;
- clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
- if (!clki) {
- ret = -ENOMEM;
- goto out;
- }
- clki->max_freq = clkfreq[i];
- clki->name = kstrdup(name, GFP_KERNEL);
- list_add_tail(&clki->list, &hwkm_dev->clk_list_head);
- }
- out:
- return ret;
- }
- static int qti_hwkm_init_clocks(struct ice_mmio_data *hwkm_dev)
- {
- int ret = -EINVAL;
- struct hwkm_clk_info *clki = NULL;
- struct device *dev = hwkm_dev->dev;
- struct list_head *head = &hwkm_dev->clk_list_head;
- if (!hwkm_dev->is_hwkm_clk_available)
- return 0;
- if (!head || list_empty(head)) {
- dev_err(dev, "%s: HWKM clock list null/empty\n", __func__);
- goto out;
- }
- list_for_each_entry(clki, head, list) {
- if (!clki->name)
- continue;
- clki->clk = devm_clk_get(dev, clki->name);
- if (IS_ERR(clki->clk)) {
- ret = PTR_ERR(clki->clk);
- dev_err(dev, "%s: %s clk get failed, %d\n",
- __func__, clki->name, ret);
- goto out;
- }
- ret = 0;
- if (clki->max_freq) {
- ret = clk_set_rate(clki->clk, clki->max_freq);
- if (ret) {
- dev_err(dev,
- "%s: %s clk set rate(%dHz) failed, %d\n",
- __func__, clki->name, clki->max_freq, ret);
- goto out;
- }
- clki->curr_freq = clki->max_freq;
- dev_dbg(dev, "%s: clk: %s, rate: %lu\n", __func__,
- clki->name, clk_get_rate(clki->clk));
- }
- }
- out:
- return ret;
- }
- static int qti_hwkm_enable_disable_clocks(struct ice_mmio_data *hwkm_dev,
- bool enable)
- {
- int ret;
- struct hwkm_clk_info *clki = NULL;
- struct device *dev = hwkm_dev->dev;
- struct list_head *head = &hwkm_dev->clk_list_head;
- if (!head || list_empty(head)) {
- dev_err(dev, "%s: HWKM clock list null/empty\n", __func__);
- ret = -EINVAL;
- goto out;
- }
- if (!hwkm_dev->is_hwkm_clk_available) {
- dev_err(dev, "%s: HWKM clock not available\n", __func__);
- ret = -EINVAL;
- goto out;
- }
- list_for_each_entry(clki, head, list) {
- if (!clki->name)
- continue;
- if (enable)
- ret = clk_prepare_enable(clki->clk);
- else
- clk_disable_unprepare(clki->clk);
- if (ret) {
- dev_err(dev, "Unable to %s HWKM clock\n",
- enable?"enable":"disable");
- goto out;
- }
- }
- out:
- return ret;
- }
- int qti_hwkm_clocks(bool on)
- {
- int ret;
- ret = qti_hwkm_enable_disable_clocks(mmio_data_ref, on);
- if (ret) {
- pr_err("%s:%pK Could not enable/disable clocks\n",
- __func__, mmio_data_ref);
- }
- return ret;
- }
- EXPORT_SYMBOL(qti_hwkm_clocks);
- static int qti_hwkm_get_device_tree_data(struct platform_device *pdev,
- struct ice_mmio_data *hwkm_dev)
- {
- struct device *dev = &pdev->dev;
- int ret = 0;
- hwkm_dev->km_res = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "km_master");
- if (!hwkm_dev->km_res) {
- pr_err("%s: No memory available for IORESOURCE\n", __func__);
- return -ENOMEM;
- }
- hwkm_dev->km_base = devm_ioremap_resource(dev, hwkm_dev->km_res);
- if (IS_ERR(hwkm_dev->km_base)) {
- ret = PTR_ERR(hwkm_dev->km_base);
- pr_err("%s: Error = %d mapping HWKM memory\n", __func__, ret);
- goto out;
- }
- hwkm_dev->is_hwkm_clk_available = of_property_read_bool(
- dev->of_node, "qcom,enable-hwkm-clk");
- if (hwkm_dev->is_hwkm_clk_available) {
- ret = qti_hwkm_parse_clock_info(pdev, hwkm_dev);
- if (ret) {
- pr_err("%s: qti_hwkm_parse_clock_info failed (%d)\n",
- __func__, ret);
- goto out;
- }
- }
- out:
- return ret;
- }
- int qti_hwkm_handle_cmd(struct hwkm_cmd *cmd, struct hwkm_rsp *rsp)
- {
- switch (cmd->op) {
- case SET_TPKEY:
- return qti_handle_set_tpkey(mmio_data_ref, cmd, rsp);
- case KEY_UNWRAP_IMPORT:
- return qti_handle_key_unwrap_import(mmio_data_ref, cmd, rsp);
- case KEY_SLOT_CLEAR:
- return qti_handle_keyslot_clear(mmio_data_ref, cmd, rsp);
- case KEY_SLOT_RDWR:
- return qti_handle_keyslot_rdwr(mmio_data_ref, cmd, rsp);
- case SYSTEM_KDF:
- return qti_handle_system_kdf(mmio_data_ref, cmd, rsp);
- case NIST_KEYGEN:
- case KEY_WRAP_EXPORT:
- case QFPROM_KEY_RDWR: /* cmd for HW initialization cmd only */
- default:
- return -EINVAL;
- }
- return 0;
- }
- EXPORT_SYMBOL(qti_hwkm_handle_cmd);
- static void qti_hwkm_configure_slot_access(struct ice_mmio_data *mmio_data)
- {
- qti_hwkm_writel(mmio_data, 0xffffffff,
- QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_0, ICEMEM_SLAVE);
- qti_hwkm_writel(mmio_data, 0xffffffff,
- QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_1, ICEMEM_SLAVE);
- qti_hwkm_writel(mmio_data, 0xffffffff,
- QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_2, ICEMEM_SLAVE);
- qti_hwkm_writel(mmio_data, 0xffffffff,
- QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_3, ICEMEM_SLAVE);
- qti_hwkm_writel(mmio_data, 0xffffffff,
- QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_4, ICEMEM_SLAVE);
- }
- static int qti_hwkm_check_bist_status(struct ice_mmio_data *mmio_data)
- {
- if (!qti_hwkm_testb(mmio_data, QTI_HWKM_ICE_RG_TZ_KM_STATUS,
- BIST_DONE, ICEMEM_SLAVE)) {
- pr_err("%s: Error with BIST_DONE\n", __func__);
- return -EINVAL;
- }
- if (!qti_hwkm_testb(mmio_data, QTI_HWKM_ICE_RG_TZ_KM_STATUS,
- CRYPTO_LIB_BIST_DONE, ICEMEM_SLAVE)) {
- pr_err("%s: Error with CRYPTO_LIB_BIST_DONE\n", __func__);
- return -EINVAL;
- }
- if (!qti_hwkm_testb(mmio_data, QTI_HWKM_ICE_RG_TZ_KM_STATUS,
- BOOT_CMD_LIST1_DONE, ICEMEM_SLAVE)) {
- pr_err("%s: Error with BOOT_CMD_LIST1_DONE\n", __func__);
- return -EINVAL;
- }
- if (!qti_hwkm_testb(mmio_data, QTI_HWKM_ICE_RG_TZ_KM_STATUS,
- BOOT_CMD_LIST0_DONE, ICEMEM_SLAVE)) {
- pr_err("%s: Error with BOOT_CMD_LIST0_DONE\n", __func__);
- return -EINVAL;
- }
- if (!qti_hwkm_testb(mmio_data, QTI_HWKM_ICE_RG_TZ_KM_STATUS,
- KT_CLEAR_DONE, ICEMEM_SLAVE)) {
- pr_err("%s: KT_CLEAR_DONE\n", __func__);
- return -EINVAL;
- }
- return 0;
- }
- static int qti_hwkm_ice_init_sequence(struct ice_mmio_data *mmio_data)
- {
- int ret;
- /* Put ICE in standard mode */
- qti_hwkm_writel(mmio_data, 0x7, QTI_HWKM_ICE_RG_TZ_KM_CTL, ICEMEM_SLAVE);
- /* Write memory barrier */
- wmb();
- ret = qti_hwkm_check_bist_status(mmio_data);
- if (ret) {
- pr_err("%s: Error in BIST initialization %d\n", __func__, ret);
- return ret;
- }
- /* Disable CRC checks */
- qti_hwkm_clearb(mmio_data, QTI_HWKM_ICE_RG_TZ_KM_CTL,
- CRC_CHECK_EN, ICEMEM_SLAVE);
- /* Write memory barrier */
- wmb();
- /* Configure key slots to be accessed by HLOS */
- qti_hwkm_configure_slot_access(mmio_data);
- /* Write memory barrier */
- wmb();
- /* Clear RSP_FIFO_FULL bit */
- qti_hwkm_setb(mmio_data,
- QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_STATUS,
- RSP_FIFO_FULL, ICEMEM_SLAVE);
- /* Write memory barrier */
- wmb();
- return ret;
- }
- static void qti_hwkm_enable_slave_receive_mode(
- const struct ice_mmio_data *mmio_data)
- {
- qti_hwkm_clearb(mmio_data,
- QTI_HWKM_ICE_RG_TZ_TPKEY_RECEIVE_CTL, TPKEY_EN, ICEMEM_SLAVE);
- /* Write memory barrier */
- wmb();
- qti_hwkm_writel(mmio_data, ICEMEM_SLAVE_TPKEY_VAL,
- QTI_HWKM_ICE_RG_TZ_TPKEY_RECEIVE_CTL, ICEMEM_SLAVE);
- /* Write memory barrier */
- wmb();
- }
- static void qti_hwkm_disable_slave_receive_mode(
- struct ice_mmio_data *mmio_data)
- {
- qti_hwkm_clearb(mmio_data,
- QTI_HWKM_ICE_RG_TZ_TPKEY_RECEIVE_CTL, TPKEY_EN, ICEMEM_SLAVE);
- /* Write memory barrier */
- wmb();
- }
- static void qti_hwkm_check_tpkey_status(struct ice_mmio_data *mmio_data)
- {
- int val;
- val = qti_hwkm_readl(mmio_data,
- QTI_HWKM_ICE_RG_TZ_TPKEY_RECEIVE_STATUS, ICEMEM_SLAVE);
- pr_debug("%s: Tpkey receive status 0x%x\n", __func__, val);
- }
- static int qti_hwkm_set_tpkey(struct ice_mmio_data *mmio_data)
- {
- int err;
- struct hwkm_cmd cmd_settpkey = {0};
- struct hwkm_rsp rsp_settpkey = {0};
- cmd_settpkey.op = SET_TPKEY;
- cmd_settpkey.set_tpkey.sks = KM_MASTER_TPKEY_SLOT;
- qti_hwkm_enable_slave_receive_mode(mmio_data);
- err = qti_hwkm_handle_cmd(&cmd_settpkey, &rsp_settpkey);
- if (err) {
- pr_err("%s: Error with Set TP key in master %d\n", __func__,
- err);
- return -EINVAL;
- }
- qti_hwkm_check_tpkey_status(mmio_data);
- qti_hwkm_disable_slave_receive_mode(mmio_data);
- return 0;
- }
- int qti_hwkm_init(const struct ice_mmio_data *mmio_data)
- {
- int ret;
- pr_debug("%s %d: HWKM init starts\n", __func__, __LINE__);
- if (!mmio_data->ice_hwkm_mmio || !mmio_data->ice_base_mmio) {
- pr_err("%s: HWKM ICE slave mmio invalid\n", __func__);
- return -EINVAL;
- }
- mmio_data_ref->ice_hwkm_mmio = mmio_data->ice_hwkm_mmio;
- mmio_data_ref->ice_base_mmio = mmio_data->ice_base_mmio;
- ret = qti_hwkm_ice_init_sequence(mmio_data_ref);
- if (ret) {
- pr_err("%s: Error in ICE init sequence %d\n", __func__, ret);
- return ret;
- }
- ret = qti_hwkm_set_tpkey(mmio_data_ref);
- if (ret) {
- pr_err("%s: Error setting ICE to receive %d\n", __func__, ret);
- return ret;
- }
- /* Write memory barrier */
- wmb();
- pr_debug("%s %d: HWKM init ends\n", __func__, __LINE__);
- return ret;
- }
- EXPORT_SYMBOL(qti_hwkm_init);
- static int qti_hwkm_probe(struct platform_device *pdev)
- {
- struct ice_mmio_data *hwkm_dev;
- int ret;
- pr_debug("%s %d: HWKM probe start\n", __func__, __LINE__);
- if (!pdev) {
- pr_err("%s: Invalid platform_device passed\n", __func__);
- return -EINVAL;
- }
- hwkm_dev = kzalloc(sizeof(struct ice_mmio_data), GFP_KERNEL);
- if (!hwkm_dev) {
- ret = -ENOMEM;
- pr_err("%s: Error %d allocating memory for HWKM device\n",
- __func__, ret);
- goto err_hwkm_dev;
- }
- hwkm_dev->dev = &pdev->dev;
- if (!hwkm_dev->dev) {
- ret = -EINVAL;
- pr_err("%s: Invalid device passed in platform_device\n",
- __func__);
- goto err_hwkm_dev;
- }
- if (pdev->dev.of_node)
- ret = qti_hwkm_get_device_tree_data(pdev, hwkm_dev);
- else {
- ret = -EINVAL;
- pr_err("%s: HWKM device node not found\n", __func__);
- }
- if (ret)
- goto err_hwkm_dev;
- ret = qti_hwkm_init_clocks(hwkm_dev);
- if (ret) {
- pr_err("%s: Error initializing clocks %d\n", __func__, ret);
- goto err_hwkm_dev;
- }
- hwkm_dev->is_hwkm_enabled = true;
- mmio_data_ref = hwkm_dev;
- platform_set_drvdata(pdev, hwkm_dev);
- pr_err("%s %d:HWKM probe ends\n", __func__, __LINE__);
- return ret;
- err_hwkm_dev:
- mmio_data_ref = NULL;
- kfree(hwkm_dev);
- return ret;
- }
- static int qti_hwkm_remove(struct platform_device *pdev)
- {
- kfree(mmio_data_ref);
- return 0;
- }
- static const struct of_device_id qti_hwkm_match[] = {
- { .compatible = "qcom,hwkm"},
- {},
- };
- MODULE_DEVICE_TABLE(of, qti_hwkm_match);
- static struct platform_driver qti_hwkm_driver = {
- .probe = qti_hwkm_probe,
- .remove = qti_hwkm_remove,
- .driver = {
- .name = "qti_hwkm",
- .of_match_table = qti_hwkm_match,
- },
- };
- module_platform_driver(qti_hwkm_driver);
- MODULE_LICENSE("GPL");
- MODULE_DESCRIPTION("QTI Hardware Key Manager library");
|