/**************************************************************************** * * Copyright (c) 2014 - 2019 Samsung Electronics Co., Ltd. All rights reserved * ****************************************************************************/ #ifndef _SCSC_CORE_H #define _SCSC_CORE_H #include #include #include "scsc_mifram.h" #define SCSC_PANIC_CODE_FW 0 #define SCSC_PANIC_CODE_HOST 1 #define SCSC_FW_EVENT_FAILURE 0 #define SCSC_FW_EVENT_MOREDUMP_COMPLETE 1 /** The following flags define the pools that can used for memory allocation. * To be used with scsc_mx_service_mifram_alloc_extended **/ /* Standard memory allocation */ #define MIFRAMMAN_MEM_POOL_GENERIC 1 /* Used for buffers containing logs that will not be dumped by moredump */ #define MIFRAMMAN_MEM_POOL_LOGGING 2 struct device; struct firmware; struct scsc_mx; enum scsc_service_id { SCSC_SERVICE_ID_NULL = 0, SCSC_SERVICE_ID_WLAN = 1, SCSC_SERVICE_ID_BT = 2, SCSC_SERVICE_ID_ANT = 3, SCSC_SERVICE_ID_R4DBG = 4, SCSC_SERVICE_ID_ECHO = 5, SCSC_SERVICE_ID_DBG_SAMPLER = 6, SCSC_SERVICE_ID_CLK20MHZ = 7, SCSC_SERVICE_ID_FM = 8, SCSC_SERVICE_ID_INVALID = 0xff, }; #ifdef CONFIG_SCSC_QOS #define SCSC_SERVICE_TOTAL 9 #endif enum scsc_module_client_reason { SCSC_MODULE_CLIENT_REASON_HW_PROBE = 0, SCSC_MODULE_CLIENT_REASON_HW_REMOVE = 1, SCSC_MODULE_CLIENT_REASON_RECOVERY = 2, SCSC_MODULE_CLIENT_REASON_INVALID = 0xff, }; #ifdef CONFIG_SCSC_QOS enum scsc_qos_config { SCSC_QOS_DISABLED = 0, SCSC_QOS_MIN = 1, SCSC_QOS_MED = 2, SCSC_QOS_MAX = 3, }; #endif /* SYSTEM ERROR SUB-SYSTEMS */ #define SYSERR_SUBSYS_COMMON (0) #define SYSERR_SUBSYS_BT (1) #define SYSERR_SUBSYS_WLAN (2) #define SYSERR_SUBSYS_HOST (8) /* SYSTEM ERROR levels */ /* System Error level 1 * Minor warning from firmware * Should not be escalted by driver */ #define MX_SYSERR_LEVEL_1 (1) /* System Error level 2 * More severe warning from firmware * May be escalated by driver */ #define MX_SYSERR_LEVEL_2 (2) /* System Error level 2 * Minor error handled in firmware * may be escalated by driver */ #define MX_SYSERR_LEVEL_3 (3) /* System Error level 3 * More severe error handled in firmware * May be escalated by driver */ #define MX_SYSERR_LEVEL_4 (4) /* System Error level 5 * Firmware requested service restart * May be escalated by driver */ #define MX_SYSERR_LEVEL_5 (5) /* System Error level 5 * Firmware requested service restart (firmware may have restarted some hardware) * May be escalated by driver */ #define MX_SYSERR_LEVEL_6 (6) /* System Error level 7 * Firmware halt and full restart required */ #define MX_SYSERR_LEVEL_7 (7) /* System Error level 7 * Firmware halt and full restart (not just drivers) required */ #define MX_SYSERR_LEVEL_8 (8) /* Null error code */ #define MX_NULL_SYSERR (0xFFFF) /* Details for decoding */ #define SYSERR_SUB_CODE_POSN (0) #define SYSERR_SUB_CODE_MASK (0xFFFF) #define SYSERR_SUB_SYSTEM_POSN (12) #define SYSERR_SUB_SYSTEM_MASK (0xF) #define SYSERR_LEVEL_POSN (24) #define SYSERR_LEVEL_MASK (0xF) #define SYSERR_TYPE_POSN (28) #define SYSERR_TYPE_MASK (0xFF) #define SYSERR_SUB_SYSTEM_HOST (8) /* Core Driver Module registration */ struct scsc_mx_module_client { char *name; void (*probe)(struct scsc_mx_module_client *module_client, struct scsc_mx *mx, enum scsc_module_client_reason reason); void (*remove)(struct scsc_mx_module_client *module_client, struct scsc_mx *mx, enum scsc_module_client_reason reason); }; /* Service Client interface */ /* Decoded syserr_code */ struct mx_syserr_decode { u8 subsys; u8 level; u16 type; u16 subcode; }; struct scsc_service_client; struct scsc_service_client { /** Called on Maxwell System Error. The Client should use its internal state information * and the information provided by this call to return an appropriate recovery level * which must be greater than or equal to that passed in as parameter within the * mx_syserr_decode structure. */ u8 (*failure_notification)(struct scsc_service_client *client, struct mx_syserr_decode *err); /** Called on Maxwell failure requiring a service restart or full chip restart. * The level within the mx_syserr_decode structure indicates the recover level taking place. * The Client should Stop all SDRAM & MIF Mailbox access as fast as possible * and inform the Manager by calling client_stopped(). The boolean return value * indicates that this failure should trigger an slsi_send_hanged_vendor_event * if WLAN is active (common code will ensure this happens by passing scsc_syserr_code * parameter with a value other than MX_NULL_SYSERR when failure_reset is called subsequently) */ bool (*stop_on_failure_v2)(struct scsc_service_client *client, struct mx_syserr_decode *err); /* Old version to be depricated */ void (*stop_on_failure)(struct scsc_service_client *client); /** Called when Maxwell failure has been handled and the Maxwell has been * reset if the level has demanded it. The Client should assume that any Maxwell * resources it held are invalid. If a scsc_syserr_code other than MX_NULL_SYSERR is provided, * then this may be propogated by the WLAN driver as a slsi_send_hanged_vendor_event * to notify the host of the failure and its cause */ void (*failure_reset_v2)(struct scsc_service_client *client, u8 level, u16 scsc_syserr_code); /* Old version to be depricated */ void (*failure_reset)(struct scsc_service_client *client, u16 scsc_panic_code); /* called when AP processor is going into suspend. */ int (*suspend)(struct scsc_service_client *client); /* called when AP processor has resumed */ int (*resume)(struct scsc_service_client *client); /* called when log collection has been triggered */ void (*log)(struct scsc_service_client *client, u16 reason); }; /* * This must be used by FM Radio Service only. Other services must not use it. * FM Radio client must allocate memory for this structure using scsc_mx_service_mifram_alloc() * and pass this structure as a ref parameter to scsc_mx_service_start(). * The version of fm_ldo_conf (the LDO configuration structure) must be written * to the version field by the FM Radio Service and confirmed to match the define by the firmware. * Increment the version (FM_LDO_CONFIG_VERSION) when changing the layout of the structure. */ #define FM_LDO_CONFIG_VERSION 0 struct fm_ldo_conf { uint32_t version; /* FM_LDO_CONFIG_VERSION */ uint32_t ldo_on; }; /* Parameters to pass from FM radio client driver to WLBT drivers */ struct wlbt_fm_params { u32 freq; /* Frequency (Hz) in use by FM radio */ }; /* Shared Data BT-ABOX */ struct scsc_btabox_data { unsigned long btaboxmem_start; size_t btaboxmem_size; }; #define PANIC_RECORD_SIZE 64 #define PANIC_STACK_RECORD_SIZE 256 #define PANIC_RECORD_DUMP_BUFFER_SZ 4096 /* WARNING: THIS IS INTERRUPT CONTEXT! * here: some serious warnings about not blocking or doing anything lengthy at all */ typedef void (*scsc_mifintrbit_handler)(int which_bit, void *data); /* * Core Module Inteface */ int scsc_mx_module_register_client_module(struct scsc_mx_module_client *module_client); void scsc_mx_module_unregister_client_module(struct scsc_mx_module_client *module_client); int scsc_mx_module_reset(void); /* * Core Instance interface */ /** 1st thing to do is call open and return service managment interface*/ struct scsc_service *scsc_mx_service_open(struct scsc_mx *mx, enum scsc_service_id id, struct scsc_service_client *client, int *status); /* * Service interface */ /** pass a portable dram reference and returns kernel pointer (basically is dealing with the pointers) */ void *scsc_mx_service_mif_addr_to_ptr(struct scsc_service *service, scsc_mifram_ref ref); void *scsc_mx_service_mif_addr_to_phys(struct scsc_service *service, scsc_mifram_ref ref); int scsc_mx_service_mif_ptr_to_addr(struct scsc_service *service, void *mem_ptr, scsc_mifram_ref *ref); int scsc_mx_service_start(struct scsc_service *service, scsc_mifram_ref ref); int scsc_mx_service_stop(struct scsc_service *service); int scsc_mx_service_close(struct scsc_service *service); int scsc_mx_service_mif_dump_registers(struct scsc_service *service); /** Signal a failure detected by the Client. This will trigger the systemwide * MX_SYSERR_LEVEL_7 failure handling procedure: _All_ Clients will be called back via * their stop_on_failure() handler as a side-effect. */ void scsc_mx_service_service_failed(struct scsc_service *service, const char *reason); /* MEMORY Interface*/ /** Allocate a contiguous block of SDRAM accessible to Client Driver. The memory will be allocated * from generic pool (MIFRAMMAN_MEM_POOL_GENERIC) */ int scsc_mx_service_mifram_alloc(struct scsc_service *service, size_t nbytes, scsc_mifram_ref *ref, u32 align); /* Same as scsc_mx_service_mifram_alloc but allows to specify flags (MIFRAMMAN_MEM_POOL_XX). * So, for example, to allocate memory from the logging pool use MIFRAMMAN_MEM_POOL_LOGGING. */ int scsc_mx_service_mifram_alloc_extended(struct scsc_service *service, size_t nbytes, scsc_mifram_ref *ref, u32 align, uint32_t flags); struct scsc_bt_audio_abox *scsc_mx_service_get_bt_audio_abox(struct scsc_service *service); struct mifabox *scsc_mx_service_get_aboxram(struct scsc_service *service); /** Free a contiguous block of SDRAM */ void scsc_mx_service_mifram_free(struct scsc_service *service, scsc_mifram_ref ref); void scsc_mx_service_mifram_free_extended(struct scsc_service *service, scsc_mifram_ref ref, uint32_t flags); /* MBOX Interface */ /** Allocate n contiguous mailboxes. Outputs index of first mbox, returns FALSE if can’t allocate n contiguous mailboxes. */ bool scsc_mx_service_alloc_mboxes(struct scsc_service *service, int n, int *first_mbox_index); /** Free n contiguous mailboxes. */ void scsc_service_free_mboxes(struct scsc_service *service, int n, int first_mbox_index); /** Get kernel-space pointer to a mailbox. * The pointer can be cached as it is guaranteed not to change between service start & stop. **/ u32 *scsc_mx_service_get_mbox_ptr(struct scsc_service *service, int mbox_index); /* IRQ Interface */ /* Getters/Setters */ /* From R4/M4 */ int scsc_service_mifintrbit_bit_mask_status_get(struct scsc_service *service); int scsc_service_mifintrbit_get(struct scsc_service *service); void scsc_service_mifintrbit_bit_clear(struct scsc_service *service, int which_bit); void scsc_service_mifintrbit_bit_mask(struct scsc_service *service, int which_bit); void scsc_service_mifintrbit_bit_unmask(struct scsc_service *service, int which_bit); /* To R4/M4 */ enum scsc_mifintr_target { SCSC_MIFINTR_TARGET_R4 = 0, SCSC_MIFINTR_TARGET_M4 = 1 }; void scsc_service_mifintrbit_bit_set(struct scsc_service *service, int which_bit, enum scsc_mifintr_target dir); /* Register an interrupt handler -TOHOST direction. * Function returns the IRQ associated , -EIO if all interrupts have been assigned */ int scsc_service_mifintrbit_register_tohost(struct scsc_service *service, scsc_mifintrbit_handler handler, void *data); /* Unregister an interrupt handler associated with a bit -TOHOST direction */ int scsc_service_mifintrbit_unregister_tohost(struct scsc_service *service, int which_bit); /* Get an interrupt bit associated with the target (R4/M4) -FROMHOST direction * Function returns the IRQ bit associated , -EIO if error */ int scsc_service_mifintrbit_alloc_fromhost(struct scsc_service *service, enum scsc_mifintr_target dir); /* Free an interrupt bit associated with the target (R4/M4) -FROMHOST direction * Function returns the 0 if succedes , -EIO if error */ int scsc_service_mifintrbit_free_fromhost(struct scsc_service *service, int which_bit, enum scsc_mifintr_target dir); /* * Return a kernel device associated 1:1 with the Maxwell instance. * This is published only for the purpose of associating service drivers * with a Maxwell instance for logging purposes. Clients should not make * any assumptions about the device type. In some configurations this may * be the associated host-interface device (AXI/PCIe), * but this may change in future. */ struct device *scsc_service_get_device(struct scsc_service *service); struct device *scsc_service_get_device_by_mx(struct scsc_mx *mx); int scsc_service_force_panic(struct scsc_service *service); /* * API to share /sys/wifi kobject between core and wifi driver modules. * Depending upon the order of loading respective drivers, a kobject is * created and shared with the other driver. This convoluted implementation * is required as we need the common kobject associated with "/sys/wifi" directory * when creating a file underneth. core driver (mxman.c) need to create "memdump" * and wifi driver (dev.c,mgt.c) needs to create "mac_addr" files respectively. */ struct kobject *mxman_wifi_kobject_ref_get(void); void mxman_wifi_kobject_ref_put(void); #ifdef CONFIG_SCSC_SMAPPER /* SMAPPER Interface */ /* Configure smapper. Function should configure smapper FW memory map, range, and granularity */ void scsc_service_mifsmapper_configure(struct scsc_service *service, u32 granularity); /* Allocate large/small entries bank. Outputs index of bank, returns -EIO if can’t allocate any banks. */ /* Function also returns by the numbers of entries that could be used in the bank as the number of entries * is HW dependent (entries/granurality/memory window in FW) */ int scsc_service_mifsmapper_alloc_bank(struct scsc_service *service, bool large_bank, u32 entry_size, u16 *entries); /* Free large/small entries bank */ int scsc_service_mifsmapper_free_bank(struct scsc_service *service, u8 bank); /* Get number entries, returns error if entries have not been allocated */ int scsc_service_mifsmapper_get_entries(struct scsc_service *service, u8 bank, u8 num_entries, u8 *entries); /* Free number entries, returns error if entries have not been allocated */ int scsc_service_mifsmapper_free_entries(struct scsc_service *service, u8 bank, u8 num_entries, u8 *entries); /* Program SRAM entry */ int scsc_service_mifsmapper_write_sram(struct scsc_service *service, u8 bank, u8 num_entries, u8 first_entry, dma_addr_t *addr); u32 scsc_service_mifsmapper_get_bank_base_address(struct scsc_service *service, u8 bank); /* Get SMAPPER aligment */ u16 scsc_service_get_alignment(struct scsc_service *service); #endif #ifdef CONFIG_SCSC_QOS int scsc_service_pm_qos_add_request(struct scsc_service *service, enum scsc_qos_config config); int scsc_service_pm_qos_update_request(struct scsc_service *service, enum scsc_qos_config config); int scsc_service_pm_qos_remove_request(struct scsc_service *service); int scsc_service_set_affinity_cpu(struct scsc_service *service, u8 cpu); #endif /* Return the panic record */ int scsc_service_get_panic_record(struct scsc_service *service, u8 *dst, u16 max_size); /* MXLOGGER API */ /* If there is no service/mxman associated, register the observer as global (will affect all the mx instanes)*/ /* Users of these functions should ensure that the registers/unregister functions are balanced (i.e. if observer is registed as global, * it _has_ to unregister as global) */ int scsc_service_register_observer(struct scsc_service *service, char *name); /* Unregister an observer */ int scsc_service_unregister_observer(struct scsc_service *service, char *name); /* Reads a configuration file into memory. * * Path is relative to the currently selected firmware configuration * subdirectory. * Returns pointer to data or NULL if file not found. * Call mx140_file_release_conf()to release the memory. */ int mx140_file_request_conf(struct scsc_mx *mx, const struct firmware **conf, const char *config_path, const char *filename); /* Reads a debug configuration file into memory. * * Path is relative to the currently selected firmware configuration * subdirectory. * Returns pointer to data or NULL if file not found. * Call mx140_file_release_conf()to release the memory. */ int mx140_file_request_debug_conf(struct scsc_mx *mx, const struct firmware **conf, const char *config_path); /* Read device configuration file into memory. * * Path is relative to the device configuration directory. * Returns pointer to data or NULL if file not found. * Call mx140_file_release_conf() to release the memory. * This call is only used for configuration files that are * device instance specific (e.g. mac addresses) */ int mx140_file_request_device_conf(struct scsc_mx *mx, const struct firmware **conf, const char *config_path); /* Release configuration file memory * * If conf is NULL, has no effect. */ void mx140_file_release_conf(struct scsc_mx *mx, const struct firmware *conf); /* Read device configuration file into memory. * * Path is absolute. * Returns pointer to data or NULL if file not found. * Call mx140_release_file() to release the memory. */ int mx140_request_file(struct scsc_mx *mx, char *path, const struct firmware **firmp); /* Release configuration file memory allocated with mx140_request_file() * * If firmp is NULL, has no effect. */ int mx140_release_file(struct scsc_mx *mx, const struct firmware *firmp); /* 20 MHz clock API. * The mx140 device uses a clock that is also required by the USB driver. * This API allows the USB/clock driver to inform the mx140 driver that the * clock is required and that it must boot and/or keep the clock running. */ enum mx140_clk20mhz_status { MX140_CLK_SUCCESS = 0, /* Returned successfully */ MX140_CLK_STARTED, /* mx140 has started the clock */ MX140_CLK_STOPPED, /* mx140 has stopped the clock */ MX140_CLK_NOT_STARTED, /* failed to start the clock */ MX140_CLK_NOT_STOPPED, /* failed to stop the clock */ MX140_CLK_ASYNC_FAIL, /* mx140 failure, async call */ }; /* Register for 20 MHz clock API callbacks * * Parameters: * client_cb: * If client provides non-NULL client_cb, the request is asynchronous and * the client will be called back when the clock service is started. * If client_cb is NULL, the request is blocking. * data: * opaque context for the client, and will be passed back in any callback * * Note it is possible that the callback may be made in the context of the * calling request/release function. * * Returns 0 on success */ int mx140_clk20mhz_register(void (*client_cb)(void *data, enum mx140_clk20mhz_status event), void *data); /* Unregister for 20 MHz clock API callbacks. * After this call is made, the mx140 driver will no longer call back. */ void mx140_clk20mhz_unregister(void); /* Client request that the clock be available. * * If a callback was installed via mx140_clk20mhz_register(), the mx140 driver * will call back when the clock is available. If no callback was installed, * the request is blocking and will return when the clock is running. * * Returns: * mx140_clk20mhz_status if a blocking attempt was made to start the clock, * MX140_CLK_SUCCESS if the request will happen asynchronously, or, * -ve error code on other error. * */ int mx140_clk20mhz_request(void); /* Client informs that the clock is no longer needed * * Returns: * mx140_clk20mhz_status if a blocking attempt was made to stop the clock, * MX140_CLK_SUCCESS if the request will happen asynchronously, or, * -ve error code on other error. */ int mx140_clk20mhz_release(void); /* Client requests that FM LDO be available. * * Returns: * 0 on success or -ve error code on error. * */ int mx250_fm_request(void); /* Client informs that the LDO is no longer needed * * Returns: * 0 on success or -ve error code on error. */ int mx250_fm_release(void); /* FM client informs of parameter change. * * mx250_fm_request() must have been called first. * * Returns: * None */ void mx250_fm_set_params(struct wlbt_fm_params *info); /* * for set test mode. * */ bool slsi_is_rf_test_mode_enabled(void); int mx140_log_dump(void); void mxman_get_fw_version(char *version, size_t ver_sz); void mxman_get_driver_version(char *version, size_t ver_sz); int mxman_register_firmware_notifier(struct notifier_block *nb); int mxman_unregister_firmware_notifier(struct notifier_block *nb); /* Status of WLBT autorecovery on the platform * * Returns: * false - enabled, true disabled */ bool mxman_recovery_disabled(void); #endif