diff options
-rw-r--r-- | .gitreview | 3 | ||||
-rw-r--r-- | drivers/bluetooth/pistachio/img-bt-main.c | 34 | ||||
-rw-r--r-- | drivers/bluetooth/pistachio/img-hostport-main.c | 119 | ||||
-rw-r--r-- | drivers/bluetooth/pistachio/img-hostport-main.h | 10 | ||||
-rw-r--r-- | drivers/bluetooth/pistachio/img-transport.h | 27 | ||||
-rw-r--r-- | drivers/clk/pistachio/clk-pistachio.c | 4 | ||||
-rw-r--r-- | drivers/clk/pistachio/clk-pll.c | 28 | ||||
-rw-r--r-- | include/dt-bindings/clock/pistachio-clk.h | 3 |
8 files changed, 146 insertions, 82 deletions
diff --git a/.gitreview b/.gitreview index d195cc2937e..0c9183cec91 100644 --- a/.gitreview +++ b/.gitreview @@ -1,9 +1,8 @@ [gerrit] host=imgworks.imgtec.com port=29418 -project=linux_kernel +project=systems/linux defaultremote=imgsystems defaultbranch=4.1-imgsystems defaultrebase=0 defaultdraft=1 - diff --git a/drivers/bluetooth/pistachio/img-bt-main.c b/drivers/bluetooth/pistachio/img-bt-main.c index 4e98c3c5e7c..d4202e76307 100644 --- a/drivers/bluetooth/pistachio/img-bt-main.c +++ b/drivers/bluetooth/pistachio/img-bt-main.c @@ -62,6 +62,8 @@ static const char *client_name = "img-bt"; #define RPU_ACK(length) ((u16)(length | 0x8000)) #define RPU_REQ(length) ((u16)(length & 0x7FFF)) +#define BLUETOOTH_ID 1 + typedef void __iomem *ioaddr_t; /* @@ -196,7 +198,7 @@ static void req_from_controller(struct work_struct *tbd) gateway_send(pld); circ_buf_ext_give(&xmit_buffers.rx, user_data_length); - img_transport_notify(RPU_ACK(user_data_length)); + img_transport_notify(RPU_ACK(user_data_length), BLUETOOTH_ID); exit: kfifo_put(&work_depot, work); @@ -222,7 +224,7 @@ static void req_to_controller(struct work_struct *tbd) */ payload_to_circ_buf_ext(pld, &xmit_buffers.tx); payload_delete(pld); - img_transport_notify(RPU_REQ(space_needed)); + img_transport_notify(RPU_REQ(space_needed), BLUETOOTH_ID); } else { /* * Save for backlog processing, which should be fired on every @@ -247,13 +249,8 @@ static void do_tx_backlog(struct work_struct *tbd) if (kfifo_is_empty(&tx_backlog)) goto exit; - while (true) { - if (!kfifo_peek(&tx_backlog, &pld)) { - /* The fifo was empty */ - break; - } - if (circ_buf_ext_space(&xmit_buffers.tx) < payload_length(pld)) - break; + while (kfifo_peek(&tx_backlog, &pld) && + circ_buf_ext_space(&xmit_buffers.tx) >= payload_length(pld)) { length_sum += payload_length(pld); /* @@ -268,7 +265,7 @@ static void do_tx_backlog(struct work_struct *tbd) payload_delete(pld); } - img_transport_notify(RPU_REQ((u16)length_sum)); + img_transport_notify(RPU_REQ((u16)length_sum), BLUETOOTH_ID); exit: (void)kfifo_put(&work_depot, work); @@ -436,7 +433,7 @@ static void img_bt_pltfr_reg_handler_rollback(unsigned int client_id) img_transport_remove_callback(client_id); } -static int img_bt_pltfr_probe(struct platform_device *pdev) +static int __init img_bt_pltfr_probe(struct platform_device *pdev) { int result = 0; @@ -458,7 +455,7 @@ static int img_bt_pltfr_probe(struct platform_device *pdev) goto bufsetup_failed; } - result = img_bt_pltfr_reg_handler(0); + result = img_bt_pltfr_reg_handler(BLUETOOTH_ID); if (result) { err("failed to install callback in the transport interface\n"); goto callback_regist_failed; @@ -517,18 +514,7 @@ struct platform_driver img_bt_driver = { static int __init img_bt_init(void) { - int result = 0; - - result = platform_driver_register(&img_bt_driver); - if (result) { - dbg("failed to register platform driver\n"); - goto pltfr_regist_failed; - } - - return result; - -pltfr_regist_failed: - return result; + return platform_driver_probe(&img_bt_driver, img_bt_pltfr_probe); } static void __exit img_bt_exit(void) diff --git a/drivers/bluetooth/pistachio/img-hostport-main.c b/drivers/bluetooth/pistachio/img-hostport-main.c index 8f95887867c..cd88b313e5b 100644 --- a/drivers/bluetooth/pistachio/img-hostport-main.c +++ b/drivers/bluetooth/pistachio/img-hostport-main.c @@ -40,6 +40,7 @@ #include <linux/proc_fs.h> #include <linux/semaphore.h> #include <linux/slab.h> +#include <linux/spinlock.h> #include <linux/clk.h> #include "img-hostport-main.h" @@ -55,7 +56,7 @@ static const char *hal_name = "img-hostport"; #define diagdbgn(format, ...) \ dbgn("%s : %d : " format, __func__, __LINE__, ## __VA_ARGS__) -#define COMMON_HOST_ID 1 +#define COMMON_HOST_ID 0 #define CALLEE_MASK 0x000000f0 #define CALLEE_SHIFT 4 #define CALLER_MASK 0x0000000f @@ -75,6 +76,11 @@ static const char * const clock_names[] = {"rpu_core", "bt", "bt_div4", static struct clk *clocks[CLK_QTY]; /* + * Forward declarations + */ +static void notify_common(u16 user_data, int user_id); + +/* * Public interface procs */ @@ -82,39 +88,44 @@ int img_transport_register_callback( img_transport_handler poke, unsigned int client_id) { - /* - * TODO: watch out for an interrupt! - * This variable has to be protected by - * a spinlock => accessor procs needed. - */ - module->rcv_handler = poke; + if (client_id > MAX_ENDPOINT_ID || module->endpoints.f[client_id]) + return -EBADSLT; + + spin_lock(module->endpoints.in_use + client_id); + module->endpoints.f[client_id] = poke; + spin_unlock(module->endpoints.in_use + client_id); - /* - * TODO: proper error reporting needed. - * For now, just succeed every time. - */ return 0; } EXPORT_SYMBOL(img_transport_register_callback); -int img_transport_notify(u16 user_data) +void img_transport_notify(u16 user_data, int user_id) { down(&host_to_uccp_core_lock); - iowrite32(0x87 << 24 | user_data << 8 | 0x00, - (void __iomem *)H2C_CMD_ADDR(module->uccp_mem_addr)); + notify_common(user_data, user_id); +} +EXPORT_SYMBOL(img_transport_notify); - /* - * TODO: for now, just succeed every time. - * Proper error reporting needed. - */ +int __must_check img_transport_notify_timeout(u16 user_data, + int user_id, + long jiffies_timeout) +{ + if (-ETIME == down_timeout(&host_to_uccp_core_lock, jiffies_timeout)) { + return -ETIME; + } + notify_common(user_data, user_id); return 0; } -EXPORT_SYMBOL(img_transport_notify); +EXPORT_SYMBOL(img_transport_notify_timeout); int img_transport_remove_callback(unsigned int client_id) { - /* TODO: proper locking */ - module->rcv_handler = NULL; + if (client_id > MAX_ENDPOINT_ID || !module->endpoints.f[client_id]) + return -EBADSLT; + + spin_lock(module->endpoints.in_use + client_id); + module->endpoints.f[client_id] = NULL; + spin_unlock(module->endpoints.in_use + client_id); return 0; } @@ -124,11 +135,26 @@ EXPORT_SYMBOL(img_transport_remove_callback); * Private procs */ +static u8 id_to_field(int id) +{ + id &= 0xF; + return (id << 4) | id; +} + +static void notify_common(u16 user_data, int user_id) +{ + iowrite32(0x87 << 24 | user_data << 8 | id_to_field(user_id), + (void __iomem *)H2C_CMD_ADDR(module->uccp_mem_addr)); +} + static irqreturn_t hal_irq_handler(int irq, void *p) { /* p is module here! */ + unsigned long flags; unsigned int reg_value; unsigned int value, caller_id, callee_id, user_message, first_bit; + img_transport_handler handler; + spinlock_t *handler_in_use; reg_value = readl((void __iomem *)(C2H_CMD_ADDR(module->uccp_mem_addr))); @@ -143,16 +169,22 @@ static irqreturn_t hal_irq_handler(int irq, void *p) /* Clear the uccp interrupt */ value = 0; value |= BIT(C_INT_CLR_SHIFT); - writel(*((unsigned long *)&(value)), - (void __iomem *)(H2C_ACK_ADDR(module->uccp_mem_addr))); + writel(value, (void __iomem *)(H2C_ACK_ADDR(module->uccp_mem_addr))); callee_id = CALLEE(reg_value); caller_id = CALLER(reg_value); user_message = USERMSG(reg_value); /* - * we are ready to release the spinlock - * once we get the all zeros message + * We are ready to release the spinlock + * once we get the all zeros message. + * + * callee_id is tainted, therefore must be checked. */ + if (callee_id > MAX_ENDPOINT_ID) { + errn("endpoint with id = %u doesn't exist", callee_id); + return IRQ_HANDLED; + } + if (COMMON_HOST_ID == callee_id) { switch (user_message) { case 0: @@ -169,10 +201,14 @@ static irqreturn_t hal_irq_handler(int irq, void *p) errn("\tuser_message : %d", user_message); } } else { - /* invoke client callback */ - /* TODO: add support for multiple IDs */ - if (NULL != module->rcv_handler) - module->rcv_handler((u16)user_message); + handler = module->endpoints.f[callee_id]; + handler_in_use = module->endpoints.in_use + callee_id; + if (NULL != handler) { + spin_lock_irqsave(handler_in_use, flags); + handler((u16)user_message); + spin_unlock_irqrestore(handler_in_use, flags); + } else + errn("endpoint with id = %u not registered", callee_id); } return IRQ_HANDLED; @@ -185,16 +221,14 @@ static void img_hostport_irq_on(void) /* Set external pin irq enable for host_irq and uccp_irq */ value = readl((void __iomem *)C_INT_ENAB_ADDR(module->uccp_mem_addr)); value |= BIT(C_INT_IRQ_ENAB_SHIFT); - writel(*((unsigned long *)&(value)), + writel(value, (void __iomem *)(C_INT_ENAB_ADDR(module->uccp_mem_addr))); /* Enable raising uccp_int when UCCP_INT = 1 */ value = 0; value |= BIT(C_INT_EN_SHIFT); - writel(*((unsigned long *)&(value)), + writel(value, (void __iomem *)(C_INT_ENABLE_ADDR(module->uccp_mem_addr))); - - return; } static void img_hostport_irq_off(void) @@ -204,16 +238,14 @@ static void img_hostport_irq_off(void) /* Reset external pin irq enable for host_irq and uccp_irq */ value = readl((void __iomem *)C_INT_ENAB_ADDR(module->uccp_mem_addr)); value &= ~(BIT(C_INT_IRQ_ENAB_SHIFT)); - writel(*((unsigned long *)&(value)), + writel(value, (void __iomem *)(C_INT_ENAB_ADDR(module->uccp_mem_addr))); /* Disable raising uccp_int when UCCP_INT = 1 */ value = 0; value &= ~(BIT(C_INT_EN_SHIFT)); - writel(*((unsigned long *)&(value)), + writel(value, (void __iomem *)(C_INT_ENABLE_ADDR(module->uccp_mem_addr))); - - return; } static int img_hostport_pltfr_irqregist(int irq_line) @@ -310,12 +342,16 @@ static void img_hostport_pltfr_memmap_rollback(void) static int img_hostport_pltfr_memsetup(void) { + int i; + module = kzalloc(sizeof(struct img_hostport), GFP_KERNEL); if (IS_ERR_OR_NULL(module)) return PTR_ERR(module); - else - return 0; + + for (i = 0; i < MAX_ENDPOINTS; i++) + spin_lock_init(module->endpoints.in_use + i); + return 0; } static void img_hostport_pltfr_memsetup_rollback(void) @@ -342,7 +378,7 @@ static void img_hostport_pltfr_clksetup_rollback(void) } -static int img_hostport_pltfr_probe(struct platform_device *pdev) +static int __init img_hostport_pltfr_probe(struct platform_device *pdev) { int result = 0; @@ -429,7 +465,8 @@ static void __exit img_hostport_leave(void) static int __init img_hostport_entry(void) { - return platform_driver_register(&img_uccp_driver); + return platform_driver_probe(&img_uccp_driver, + img_hostport_pltfr_probe); } module_init(img_hostport_entry); diff --git a/drivers/bluetooth/pistachio/img-hostport-main.h b/drivers/bluetooth/pistachio/img-hostport-main.h index c72de6933aa..4120864c75c 100644 --- a/drivers/bluetooth/pistachio/img-hostport-main.h +++ b/drivers/bluetooth/pistachio/img-hostport-main.h @@ -35,8 +35,16 @@ #include "img-transport.h" +#define MAX_ENDPOINTS 3 +#define MAX_ENDPOINT_ID (MAX_ENDPOINTS - 1) + +struct img_hostport_endpoints { + img_transport_handler f[MAX_ENDPOINTS]; + spinlock_t in_use[MAX_ENDPOINTS]; +}; + struct img_hostport { - img_transport_handler rcv_handler; + struct img_hostport_endpoints endpoints; /* RPU system bus remapped addresses */ void __iomem *uccp_mem_addr; void __iomem *uccp_base_addr; diff --git a/drivers/bluetooth/pistachio/img-transport.h b/drivers/bluetooth/pistachio/img-transport.h index 1164e342426..cd29e65058d 100644 --- a/drivers/bluetooth/pistachio/img-transport.h +++ b/drivers/bluetooth/pistachio/img-transport.h @@ -42,21 +42,36 @@ */ typedef void (*img_transport_handler)(u16 user_data); -int img_transport_notify(u16 user_data); +/* + * Note that this function may sleep forever when, + * for example, RPU is unable to respond. + * + * Possible return values: + * 0 : RPU has been notified + */ +void img_transport_notify(u16 user_data, int user_id); + +/* + * Possible return values: + * @ -ETIME : request timed out + * @ 0 : RPU has been notified + */ +int __must_check img_transport_notify_timeout(u16 user_data, + int user_id, + long jiffies_timeout); /* * Possible return values: - * @ -ENOBUFS : all handler slots in use - * @ -EBADSLT : id unavailable - * @ 0 : callback registered + * @ -EBADSLT : id unavailable + * @ 0 : callback registered */ int img_transport_register_callback(img_transport_handler, unsigned int client_id); /* * Possible return values: - * @ -EIDRM : client id not found - * @ 0 : callback removed + * @ -EBADSLT : client id not found + * @ 0 : callback removed */ int img_transport_remove_callback(unsigned int client_id); diff --git a/drivers/clk/pistachio/clk-pistachio.c b/drivers/clk/pistachio/clk-pistachio.c index f5bfee96cbe..99e177dfb2a 100644 --- a/drivers/clk/pistachio/clk-pistachio.c +++ b/drivers/clk/pistachio/clk-pistachio.c @@ -72,7 +72,7 @@ static struct pistachio_div pistachio_divs[] __initdata = { DIV(CLK_RPU_V_DIV, "rpu_v_div", "rpu_v_pll_mux", 0x21c, 2), DIV(CLK_RPU_L_DIV, "rpu_l_div", "rpu_l_mux", 0x220, 2), DIV(CLK_RPU_SLEEP_DIV, "rpu_sleep_div", "xtal", 0x224, 10), - DIV(CLK_RPU_CORE_DIV, "rpu_core_div", "rpu_core_mux", 0x228, 3), + DIV(CLK_RPU_CORE_DIV, "rpu_core_div", "rpu_core_mux_1", 0x228, 3), DIV(CLK_USB_PHY_DIV, "usb_phy_div", "sys_internal_div", 0x22c, 6), DIV(CLK_ENET_DIV, "enet_div", "enet_mux", 0x230, 6), DIV_F(CLK_UART0_INTERNAL_DIV, "uart0_internal_div", "sys_pll_mux", @@ -118,6 +118,7 @@ PNAME(mux_xtal_wifi_div4) = { "xtal", "wifi_div4" }; PNAME(mux_xtal_wifi_div8) = { "xtal", "wifi_div8" }; PNAME(mux_wifi_div4_rpu_l) = { "wifi_pll_gate", "wifi_div4_mux", "rpu_l_pll_mux" }; +PNAME(mux_rpu_core_1) = { "rpu_core_mux", "rpu_l_pll_mux"}; PNAME(mux_xtal_sys) = { "xtal", "sys_pll" }; PNAME(mux_sys_enet) = { "sys_internal_div", "enet_in" }; PNAME(mux_audio_sys) = { "audio_pll_mux", "sys_internal_div" }; @@ -138,6 +139,7 @@ static struct pistachio_mux pistachio_muxes[] __initdata = { MUX(CLK_WIFI_DIV4_MUX, "wifi_div4_mux", mux_xtal_wifi_div4, 0x200, 9), MUX(CLK_WIFI_DIV8_MUX, "wifi_div8_mux", mux_xtal_wifi_div8, 0x200, 10), MUX(CLK_RPU_CORE_MUX, "rpu_core_mux", mux_wifi_div4_rpu_l, 0x200, 11), + MUX(CLK_RPU_CORE_MUX_1, "rpu_core_mux_1", mux_rpu_core_1, 0x200, 12), MUX(CLK_SYS_PLL_MUX, "sys_pll_mux", mux_xtal_sys, 0x200, 13), MUX(CLK_ENET_MUX, "enet_mux", mux_sys_enet, 0x200, 14), MUX(CLK_EVENT_TIMER_MUX, "event_timer_mux", mux_audio_sys, 0x200, 15), diff --git a/drivers/clk/pistachio/clk-pll.c b/drivers/clk/pistachio/clk-pll.c index f1d3da44d2f..5a7b774e41f 100644 --- a/drivers/clk/pistachio/clk-pll.c +++ b/drivers/clk/pistachio/clk-pll.c @@ -112,6 +112,20 @@ static inline u32 pll_frac_get_mode(struct clk_hw *hw) return val ? PLL_MODE_INT : PLL_MODE_FRAC; } +static inline void pll_frac_set_mode(struct clk_hw *hw, u32 mode) +{ + struct pistachio_clk_pll *pll = to_pistachio_pll(hw); + u32 val; + + val = pll_readl(pll, PLL_CTRL3); + if (mode == PLL_MODE_INT) + val |= PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_DACPD; + else + val &= ~(PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_DACPD); + + pll_writel(pll, val, PLL_CTRL3); +} + static struct pistachio_pll_rate_table * pll_get_params(struct pistachio_clk_pll *pll, unsigned long fref, unsigned long fout) @@ -208,13 +222,9 @@ static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate, if (!params || !params->refdiv) return -EINVAL; - /* get operating mode and calculate vco accordingly */ + /* calculate vco */ vco = params->fref; - if (pll_frac_get_mode(hw) == PLL_MODE_INT) - vco *= params->fbdiv << 24; - else - vco *= (params->fbdiv << 24) + params->frac; - + vco *= (params->fbdiv << 24) + params->frac; vco = div64_u64(vco, params->refdiv << 24); if (vco < MIN_VCO_FRAC_FRAC || vco > MAX_VCO_FRAC_FRAC) @@ -265,6 +275,12 @@ static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate, (params->postdiv2 << PLL_FRAC_CTRL2_POSTDIV2_SHIFT); pll_writel(pll, val, PLL_CTRL2); + /* set operating mode */ + if (params->frac) + pll_frac_set_mode(hw, PLL_MODE_FRAC); + else + pll_frac_set_mode(hw, PLL_MODE_INT); + if (enabled) pll_lock(pll); diff --git a/include/dt-bindings/clock/pistachio-clk.h b/include/dt-bindings/clock/pistachio-clk.h index 039f83facb6..dfda0c330d2 100644 --- a/include/dt-bindings/clock/pistachio-clk.h +++ b/include/dt-bindings/clock/pistachio-clk.h @@ -104,8 +104,9 @@ #define CLK_SD_HOST_MUX 110 #define CLK_BT_PLL_MUX 111 #define CLK_DEBUG_MUX 112 +#define CLK_RPU_CORE_MUX_1 113 -#define CLK_NR_CLKS 113 +#define CLK_NR_CLKS 114 /* Peripheral gate clocks */ #define PERIPH_CLK_SYS 0 |