Received: by 2002:a05:6a10:206:0:0:0:0 with SMTP id 6csp2007985pxj; Sun, 13 Jun 2021 05:52:07 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxSR9RPSiFX3DH1eTXq5gRVU0pPTUErVMfU/MUaq/QycGvRL2lTtGhe7zPYlWDTI0a+uBlS X-Received: by 2002:a17:906:22c8:: with SMTP id q8mr10928282eja.12.1623588726972; Sun, 13 Jun 2021 05:52:06 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1623588726; cv=none; d=google.com; s=arc-20160816; b=OZIvNq7Ho0nOKfg7IAgP0jbc4aFqZcKcJmoOI5vGbmHIBL/PtlPUGPQQALsMverJJU VxC2rOJcmbaSNzuUECl8NaiSIEnlD20xo+ChvZJkL4FRh5T97j+2/q0T2t2PFkYqWLU5 eKho+iLL+r1OKFZ3Q2Md2ic/8RpVO+ItOy6gHBDK2nKh1yobGhvEi48DignrVi3T8HDa lW4hqyj195bbJm9i9Q8f6Vcc5TPTRAac5hJpdRQBD8Xv2ynaaT/j/1yFMqsXSp18onEI fMcnf+2jo9kvZyZNwRXtJdtt3PKX7u40pdGmidk49p/9prkWc2pOeCbSo1abIR6jqCe2 z/VA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:references:in-reply-to:message-id:date:subject :cc:to:from:ironport-sdr:ironport-sdr; bh=hfGAC3f+V8mMQNvNQPfHQETRp883mDrvvAFu7wsChII=; b=vf+gM51G/BEn3t3X7dQfcNeDc0CcJnO+cbnDXKkUAoghOq7ssGsDj8TTcRDnanTMoB tmnyALQd7ieETNVp3a6FIqMkvOmbIRkLAaOrn9MNZClrAc2XV4Pa16sY67qZ5xARPWpW AFwUlMntqQqBc2B38Mqn1D8oqbSvp+J5Ksf6/CnNG/O+Igrw5hoBD6rAuE/ReLdbVIck KJ+0PO8VvcX8q02gYBRisoNUMAOD4apO/7x+mhUeAQO65qQHhLmMydL4RVbdih2eSmVz lHr47KQktKPHgryioRZ/VJln4hF8knfA1hYWvHv8HthUsMcOYMbn3g6GcQDZR2UAtSTr HMUg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-wireless-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-wireless-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id y12si8770190eje.174.2021.06.13.05.51.29; Sun, 13 Jun 2021 05:52:06 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-wireless-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-wireless-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-wireless-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231828AbhFMMwv (ORCPT + 99 others); Sun, 13 Jun 2021 08:52:51 -0400 Received: from mga01.intel.com ([192.55.52.88]:20206 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231831AbhFMMwu (ORCPT ); Sun, 13 Jun 2021 08:52:50 -0400 IronPort-SDR: T198qnLHyFYY4oW9QyGsj5fgpHSriyZb92DVHx2xABw7V7gt9DgJiXJK14qrO13rE3djQryF0C hfTmYyDhU7TQ== X-IronPort-AV: E=McAfee;i="6200,9189,10013"; a="227158460" X-IronPort-AV: E=Sophos;i="5.83,271,1616482800"; d="scan'208";a="227158460" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Jun 2021 05:50:49 -0700 IronPort-SDR: NVqStzCqXqR0YXoxih6RyXkFzmML0JsWaUSsDADXJhUHJ4TNSVfYg+BotRS5jF43u739fz7Veh ISU5IheyLt7w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.83,271,1616482800"; d="scan'208";a="449612951" Received: from bgsxx0031.iind.intel.com ([10.106.222.40]) by orsmga008.jf.intel.com with ESMTP; 13 Jun 2021 05:50:47 -0700 From: M Chetan Kumar To: netdev@vger.kernel.org, linux-wireless@vger.kernel.org Cc: johannes@sipsolutions.net, krishna.c.sudi@intel.com, linuxwwan@intel.com Subject: [PATCH V5 03/16] net: iosm: mmio scratchpad Date: Sun, 13 Jun 2021 18:20:10 +0530 Message-Id: <20210613125023.18945-4-m.chetan.kumar@intel.com> X-Mailer: git-send-email 2.12.3 In-Reply-To: <20210613125023.18945-1-m.chetan.kumar@intel.com> References: <20210613125023.18945-1-m.chetan.kumar@intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org 1) Initializes the Scratchpad region for Host-Device communication. 2) Exposes device capabilities like chip info and device execution stages. Signed-off-by: M Chetan Kumar --- v5: no change. v4: no change. v3: no change. v2: * Removed space around the : for the bitfields. * Return proper error code instead of returning -1. --- drivers/net/wwan/iosm/iosm_ipc_mmio.c | 223 ++++++++++++++++++++++++++ drivers/net/wwan/iosm/iosm_ipc_mmio.h | 193 ++++++++++++++++++++++ 2 files changed, 416 insertions(+) create mode 100644 drivers/net/wwan/iosm/iosm_ipc_mmio.c create mode 100644 drivers/net/wwan/iosm/iosm_ipc_mmio.h diff --git a/drivers/net/wwan/iosm/iosm_ipc_mmio.c b/drivers/net/wwan/iosm/iosm_ipc_mmio.c new file mode 100644 index 000000000000..06c94b1720b6 --- /dev/null +++ b/drivers/net/wwan/iosm/iosm_ipc_mmio.c @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020-21 Intel Corporation. + */ + +#include +#include +#include +#include +#include + +#include "iosm_ipc_mmio.h" + +/* Definition of MMIO offsets + * note that MMIO_CI offsets are relative to end of chip info structure + */ + +/* MMIO chip info size in bytes */ +#define MMIO_CHIP_INFO_SIZE 60 + +/* CP execution stage */ +#define MMIO_OFFSET_EXECUTION_STAGE 0x00 + +/* Boot ROM Chip Info struct */ +#define MMIO_OFFSET_CHIP_INFO 0x04 + +#define MMIO_OFFSET_ROM_EXIT_CODE 0x40 + +#define MMIO_OFFSET_PSI_ADDRESS 0x54 + +#define MMIO_OFFSET_PSI_SIZE 0x5C + +#define MMIO_OFFSET_IPC_STATUS 0x60 + +#define MMIO_OFFSET_CONTEXT_INFO 0x64 + +#define MMIO_OFFSET_BASE_ADDR 0x6C + +#define MMIO_OFFSET_END_ADDR 0x74 + +#define MMIO_OFFSET_CP_VERSION 0xF0 + +#define MMIO_OFFSET_CP_CAPABILITIES 0xF4 + +/* Timeout in 50 msec to wait for the modem boot code to write a valid + * execution stage into mmio area + */ +#define IPC_MMIO_EXEC_STAGE_TIMEOUT 50 + +/* check if exec stage has one of the valid values */ +static bool ipc_mmio_is_valid_exec_stage(enum ipc_mem_exec_stage stage) +{ + switch (stage) { + case IPC_MEM_EXEC_STAGE_BOOT: + case IPC_MEM_EXEC_STAGE_PSI: + case IPC_MEM_EXEC_STAGE_EBL: + case IPC_MEM_EXEC_STAGE_RUN: + case IPC_MEM_EXEC_STAGE_CRASH: + case IPC_MEM_EXEC_STAGE_CD_READY: + return true; + default: + return false; + } +} + +void ipc_mmio_update_cp_capability(struct iosm_mmio *ipc_mmio) +{ + u32 cp_cap; + unsigned int ver; + + ver = ipc_mmio_get_cp_version(ipc_mmio); + cp_cap = readl(ipc_mmio->base + ipc_mmio->offset.cp_capability); + + ipc_mmio->has_mux_lite = (ver >= IOSM_CP_VERSION) && + !(cp_cap & DL_AGGR) && !(cp_cap & UL_AGGR); + + ipc_mmio->has_ul_flow_credit = + (ver >= IOSM_CP_VERSION) && (cp_cap & UL_FLOW_CREDIT); +} + +struct iosm_mmio *ipc_mmio_init(void __iomem *mmio, struct device *dev) +{ + struct iosm_mmio *ipc_mmio = kzalloc(sizeof(*ipc_mmio), GFP_KERNEL); + int retries = IPC_MMIO_EXEC_STAGE_TIMEOUT; + enum ipc_mem_exec_stage stage; + + if (!ipc_mmio) + return NULL; + + ipc_mmio->dev = dev; + + ipc_mmio->base = mmio; + + ipc_mmio->offset.exec_stage = MMIO_OFFSET_EXECUTION_STAGE; + + /* Check for a valid execution stage to make sure that the boot code + * has correctly initialized the MMIO area. + */ + do { + stage = ipc_mmio_get_exec_stage(ipc_mmio); + if (ipc_mmio_is_valid_exec_stage(stage)) + break; + + msleep(20); + } while (retries-- > 0); + + if (!retries) { + dev_err(ipc_mmio->dev, "invalid exec stage %X", stage); + goto init_fail; + } + + ipc_mmio->offset.chip_info = MMIO_OFFSET_CHIP_INFO; + + /* read chip info size and version from chip info structure */ + ipc_mmio->chip_info_version = + ioread8(ipc_mmio->base + ipc_mmio->offset.chip_info); + + /* Increment of 2 is needed as the size value in the chip info + * excludes the version and size field, which are always present + */ + ipc_mmio->chip_info_size = + ioread8(ipc_mmio->base + ipc_mmio->offset.chip_info + 1) + 2; + + if (ipc_mmio->chip_info_size != MMIO_CHIP_INFO_SIZE) { + dev_err(ipc_mmio->dev, "Unexpected Chip Info"); + goto init_fail; + } + + ipc_mmio->offset.rom_exit_code = MMIO_OFFSET_ROM_EXIT_CODE; + + ipc_mmio->offset.psi_address = MMIO_OFFSET_PSI_ADDRESS; + ipc_mmio->offset.psi_size = MMIO_OFFSET_PSI_SIZE; + ipc_mmio->offset.ipc_status = MMIO_OFFSET_IPC_STATUS; + ipc_mmio->offset.context_info = MMIO_OFFSET_CONTEXT_INFO; + ipc_mmio->offset.ap_win_base = MMIO_OFFSET_BASE_ADDR; + ipc_mmio->offset.ap_win_end = MMIO_OFFSET_END_ADDR; + + ipc_mmio->offset.cp_version = MMIO_OFFSET_CP_VERSION; + ipc_mmio->offset.cp_capability = MMIO_OFFSET_CP_CAPABILITIES; + + return ipc_mmio; + +init_fail: + kfree(ipc_mmio); + return NULL; +} + +enum ipc_mem_exec_stage ipc_mmio_get_exec_stage(struct iosm_mmio *ipc_mmio) +{ + if (!ipc_mmio) + return IPC_MEM_EXEC_STAGE_INVALID; + + return (enum ipc_mem_exec_stage)readl(ipc_mmio->base + + ipc_mmio->offset.exec_stage); +} + +void ipc_mmio_copy_chip_info(struct iosm_mmio *ipc_mmio, void *dest, + size_t size) +{ + if (ipc_mmio && dest) + memcpy_fromio(dest, ipc_mmio->base + ipc_mmio->offset.chip_info, + size); +} + +enum ipc_mem_device_ipc_state ipc_mmio_get_ipc_state(struct iosm_mmio *ipc_mmio) +{ + if (!ipc_mmio) + return IPC_MEM_DEVICE_IPC_INVALID; + + return (enum ipc_mem_device_ipc_state) + readl(ipc_mmio->base + ipc_mmio->offset.ipc_status); +} + +enum rom_exit_code ipc_mmio_get_rom_exit_code(struct iosm_mmio *ipc_mmio) +{ + if (!ipc_mmio) + return IMEM_ROM_EXIT_FAIL; + + return (enum rom_exit_code)readl(ipc_mmio->base + + ipc_mmio->offset.rom_exit_code); +} + +void ipc_mmio_config(struct iosm_mmio *ipc_mmio) +{ + if (!ipc_mmio) + return; + + /* AP memory window (full window is open and active so that modem checks + * each AP address) 0 means don't check on modem side. + */ + iowrite64_lo_hi(0, ipc_mmio->base + ipc_mmio->offset.ap_win_base); + iowrite64_lo_hi(0, ipc_mmio->base + ipc_mmio->offset.ap_win_end); + + iowrite64_lo_hi(ipc_mmio->context_info_addr, + ipc_mmio->base + ipc_mmio->offset.context_info); +} + +void ipc_mmio_set_psi_addr_and_size(struct iosm_mmio *ipc_mmio, dma_addr_t addr, + u32 size) +{ + if (!ipc_mmio) + return; + + iowrite64_lo_hi(addr, ipc_mmio->base + ipc_mmio->offset.psi_address); + writel(size, ipc_mmio->base + ipc_mmio->offset.psi_size); +} + +void ipc_mmio_set_contex_info_addr(struct iosm_mmio *ipc_mmio, phys_addr_t addr) +{ + if (!ipc_mmio) + return; + + /* store context_info address. This will be stored in the mmio area + * during IPC_MEM_DEVICE_IPC_INIT state via ipc_mmio_config() + */ + ipc_mmio->context_info_addr = addr; +} + +int ipc_mmio_get_cp_version(struct iosm_mmio *ipc_mmio) +{ + return ipc_mmio ? readl(ipc_mmio->base + ipc_mmio->offset.cp_version) : + -EFAULT; +} diff --git a/drivers/net/wwan/iosm/iosm_ipc_mmio.h b/drivers/net/wwan/iosm/iosm_ipc_mmio.h new file mode 100644 index 000000000000..bcf77aea06e7 --- /dev/null +++ b/drivers/net/wwan/iosm/iosm_ipc_mmio.h @@ -0,0 +1,193 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2020-21 Intel Corporation. + */ + +#ifndef IOSM_IPC_MMIO_H +#define IOSM_IPC_MMIO_H + +/* Minimal IOSM CP VERSION which has valid CP_CAPABILITIES field */ +#define IOSM_CP_VERSION 0x0100UL + +/* DL dir Aggregation support mask */ +#define DL_AGGR BIT(23) + +/* UL dir Aggregation support mask */ +#define UL_AGGR BIT(22) + +/* UL flow credit support mask */ +#define UL_FLOW_CREDIT BIT(21) + +/* Possible states of the IPC finite state machine. */ +enum ipc_mem_device_ipc_state { + IPC_MEM_DEVICE_IPC_UNINIT, + IPC_MEM_DEVICE_IPC_INIT, + IPC_MEM_DEVICE_IPC_RUNNING, + IPC_MEM_DEVICE_IPC_RECOVERY, + IPC_MEM_DEVICE_IPC_ERROR, + IPC_MEM_DEVICE_IPC_DONT_CARE, + IPC_MEM_DEVICE_IPC_INVALID = -1 +}; + +/* Boot ROM exit status. */ +enum rom_exit_code { + IMEM_ROM_EXIT_OPEN_EXT = 0x01, + IMEM_ROM_EXIT_OPEN_MEM = 0x02, + IMEM_ROM_EXIT_CERT_EXT = 0x10, + IMEM_ROM_EXIT_CERT_MEM = 0x20, + IMEM_ROM_EXIT_FAIL = 0xFF +}; + +/* Boot stages */ +enum ipc_mem_exec_stage { + IPC_MEM_EXEC_STAGE_RUN = 0x600DF00D, + IPC_MEM_EXEC_STAGE_CRASH = 0x8BADF00D, + IPC_MEM_EXEC_STAGE_CD_READY = 0xBADC0DED, + IPC_MEM_EXEC_STAGE_BOOT = 0xFEEDB007, + IPC_MEM_EXEC_STAGE_PSI = 0xFEEDBEEF, + IPC_MEM_EXEC_STAGE_EBL = 0xFEEDCAFE, + IPC_MEM_EXEC_STAGE_INVALID = 0xFFFFFFFF +}; + +/* mmio scratchpad info */ +struct mmio_offset { + int exec_stage; + int chip_info; + int rom_exit_code; + int psi_address; + int psi_size; + int ipc_status; + int context_info; + int ap_win_base; + int ap_win_end; + int cp_version; + int cp_capability; +}; + +/** + * struct iosm_mmio - MMIO region mapped to the doorbell scratchpad. + * @base: Base address of MMIO region + * @dev: Pointer to device structure + * @offset: Start offset + * @context_info_addr: Physical base address of context info structure + * @chip_info_version: Version of chip info structure + * @chip_info_size: Size of chip info structure + * @has_mux_lite: It doesn't support mux aggergation + * @has_ul_flow_credit: Ul flow credit support + * @has_slp_no_prot: Device sleep no protocol support + * @has_mcr_support: Usage of mcr support + */ +struct iosm_mmio { + unsigned char __iomem *base; + struct device *dev; + struct mmio_offset offset; + phys_addr_t context_info_addr; + unsigned int chip_info_version; + unsigned int chip_info_size; + u8 has_mux_lite:1, + has_ul_flow_credit:1, + has_slp_no_prot:1, + has_mcr_support:1; +}; + +/** + * ipc_mmio_init - Allocate mmio instance data + * @mmio_addr: Mapped AP base address of the MMIO area. + * @dev: Pointer to device structure + * + * Returns: address of mmio instance data or NULL if fails. + */ +struct iosm_mmio *ipc_mmio_init(void __iomem *mmio_addr, struct device *dev); + +/** + * ipc_mmio_set_psi_addr_and_size - Set start address and size of the + * primary system image (PSI) for the + * FW dowload. + * @ipc_mmio: Pointer to mmio instance + * @addr: PSI address + * @size: PSI immage size + */ +void ipc_mmio_set_psi_addr_and_size(struct iosm_mmio *ipc_mmio, dma_addr_t addr, + u32 size); + +/** + * ipc_mmio_set_contex_info_addr - Stores the Context Info Address in + * MMIO instance to share it with CP during + * mmio_init. + * @ipc_mmio: Pointer to mmio instance + * @addr: 64-bit address of AP context information. + */ +void ipc_mmio_set_contex_info_addr(struct iosm_mmio *ipc_mmio, + phys_addr_t addr); + +/** + * ipc_mmio_get_cp_version - Write context info and AP memory range addresses. + * This needs to be called when CP is in + * IPC_MEM_DEVICE_IPC_INIT state + * @ipc_mmio: Pointer to mmio instance + * + * Returns: cp version else failure value on error + */ +int ipc_mmio_get_cp_version(struct iosm_mmio *ipc_mmio); + +/** + * ipc_mmio_get_cp_version - Get the CP IPC version + * @ipc_mmio: Pointer to mmio instance + * + * Returns: version number on success and failure value on error. + */ +int ipc_mmio_get_cp_version(struct iosm_mmio *ipc_mmio); + +/** + * ipc_mmio_get_rom_exit_code - Get exit code from CP boot rom download app + * @ipc_mmio: Pointer to mmio instance + * + * Returns: exit code from CP boot rom download APP + */ +enum rom_exit_code ipc_mmio_get_rom_exit_code(struct iosm_mmio *ipc_mmio); + +/** + * ipc_mmio_get_exec_stage - Query CP execution stage + * @ipc_mmio: Pointer to mmio instance + * + * Returns: CP execution stage + */ +enum ipc_mem_exec_stage ipc_mmio_get_exec_stage(struct iosm_mmio *ipc_mmio); + +/** + * ipc_mmio_get_ipc_state - Query CP IPC state + * @ipc_mmio: Pointer to mmio instance + * + * Returns: CP IPC state + */ +enum ipc_mem_device_ipc_state +ipc_mmio_get_ipc_state(struct iosm_mmio *ipc_mmio); + +/** + * ipc_mmio_copy_chip_info - Copy size bytes of CP chip info structure + * into caller provided buffer + * @ipc_mmio: Pointer to mmio instance + * @dest: Pointer to caller provided buff + * @size: Number of bytes to copy + */ +void ipc_mmio_copy_chip_info(struct iosm_mmio *ipc_mmio, void *dest, + size_t size); + +/** + * ipc_mmio_config - Write context info and AP memory range addresses. + * This needs to be called when CP is in + * IPC_MEM_DEVICE_IPC_INIT state + * + * @ipc_mmio: Pointer to mmio instance + */ +void ipc_mmio_config(struct iosm_mmio *ipc_mmio); + +/** + * ipc_mmio_update_cp_capability - Read and update modem capability, from mmio + * capability offset + * + * @ipc_mmio: Pointer to mmio instance + */ +void ipc_mmio_update_cp_capability(struct iosm_mmio *ipc_mmio); + +#endif -- 2.25.1