aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Pozella <ian.pozella@imgtec.com>2015-06-30 16:51:44 +0100
committerIan Pozella <ian.pozella@imgtec.com>2015-06-30 16:51:44 +0100
commitcd4f0c0c1138532d9467f9e8a5c23e5c9d3aa7e0 (patch)
treeaf7448e5e94eb681f4e9f6cbcc6ee862b79514c7
parent8a68bfb2793bc0fc72bdb4ea8239c6b628327b5e (diff)
parent1b52c5584ac046d4044da91e25c20cc161d8c447 (diff)
downloadv4.1-cd4f0c0c1138532d9467f9e8a5c23e5c9d3aa7e0.tar.gz
Merge branch '4.1-imgworks' into 4.1-imgsystems
Conflicts: .gitreview Change-Id: Ib0d1f4a9327317a4126fd71c125c3988c2ff0253
-rw-r--r--.gitreview3
-rw-r--r--drivers/bluetooth/pistachio/img-bt-main.c34
-rw-r--r--drivers/bluetooth/pistachio/img-hostport-main.c119
-rw-r--r--drivers/bluetooth/pistachio/img-hostport-main.h10
-rw-r--r--drivers/bluetooth/pistachio/img-transport.h27
-rw-r--r--drivers/clk/pistachio/clk-pistachio.c4
-rw-r--r--drivers/clk/pistachio/clk-pll.c28
-rw-r--r--include/dt-bindings/clock/pistachio-clk.h3
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