ARM: tegra12: clock: Add VI and ISP shared buses
Alex Frid [Sat, 10 Aug 2013 01:24:09 +0000 (18:24 -0700)]
Created VI and ISP shared buses that connects scalable PLLC4 and
parking fixed rate PLLP to 4 shared users exposed to the nvhost VI/ISP
channels:

- via.vi.c4bus and ispa.isp.c4bus for channel A
- vib.vi.c4bus and ispb.isp.c4bus for channel B

Bus topology:

{pllc4*, pllp*} ---> c4bus
c4bus           ---> { vi.c4bus(vi*), isp.c4bus(isp*) }
vi.c4bus        ---> { via.vi.c4bus, vib.vi.c4bus }
isp.c4bus       ---> { ispa.isp.c4bus(ispa*), ispb.isp.c4bus(ispb*) }

(*) - physical clocks, all other - virtual
vvv(ppp*) - virtual shared bus user vvv with physical clock client ppp.

Bug 1328903

Change-Id: I2c347c7cd1f5cb219b5bdf76fb6749cd5d3a790b
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/260248
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>

arch/arm/mach-tegra/common.c
arch/arm/mach-tegra/tegra12_clocks.c
arch/arm/mach-tegra/tegra12_dvfs.c
drivers/video/tegra/host/t124/t124.c

index ab008fc..cd986a3 100644 (file)
@@ -456,6 +456,7 @@ static __initdata struct tegra_clk_init_table tegra12x_cbus_init_table[] = {
        { "cbus",       "pll_c",        200000000,      false },
 #endif
        { "pll_c_out1", "pll_c",        100000000,      false },
+       { "c4bus",      "pll_c4",       200000000,      false },
        { NULL,         NULL,           0,              0},
 };
 #endif
index 41d620b..e346751 100644 (file)
@@ -5524,6 +5524,34 @@ static struct clk_ops tegra_clk_shared_bus_user_ops = {
        .reset = tegra_clk_shared_bus_user_reset,
 };
 
+/* shared bus connector ops (user/bus connector to cascade shared buses) */
+static int tegra12_clk_shared_connector_update(struct clk *bus)
+{
+       unsigned long rate, old_rate;
+
+       if (detach_shared_bus)
+               return 0;
+
+       rate = tegra12_clk_shared_bus_update(bus, NULL, NULL, NULL);
+
+       old_rate = clk_get_rate_locked(bus);
+       if (rate == old_rate)
+               return 0;
+
+       return clk_set_rate_locked(bus, rate);
+}
+
+static struct clk_ops tegra_clk_shared_connector_ops = {
+       .init = tegra_clk_shared_bus_user_init,
+       .enable = tegra_clk_shared_bus_user_enable,
+       .disable = tegra_clk_shared_bus_user_disable,
+       .set_parent = tegra_clk_shared_bus_user_set_parent,
+       .set_rate = tegra_clk_shared_bus_user_set_rate,
+       .round_rate = tegra_clk_shared_bus_user_round_rate,
+       .reset = tegra_clk_shared_bus_user_reset,
+       .shared_bus_update = tegra12_clk_shared_connector_update,
+};
+
 /* coupled gate ops */
 /*
  * Some clocks may have common enable/disable control, but run at different
@@ -6977,6 +7005,21 @@ static struct clk_mux_sel mux_isp[] = {
        { 0, 0},
 };
 
+static struct raw_notifier_head c4bus_rate_change_nh;
+
+static struct clk tegra_clk_c4bus = {
+       .name      = "c4bus",
+       .parent    = &tegra_pll_c4,
+       .ops       = &tegra_clk_cbus_ops,
+       .max_rate  = 600000000,
+       .mul       = 1,
+       .div       = 1,
+       .shared_bus_backup = {
+               .input = &tegra_pll_p,
+       },
+       .rate_change_nh = &c4bus_rate_change_nh,
+};
+
 #define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
        {                                               \
                .name      = _name,                     \
@@ -7046,6 +7089,21 @@ static struct clk_mux_sel mux_isp[] = {
                        .mode = _mode,                  \
                },                                      \
        }
+#define SHARED_CONNECT(_name, _dev, _con, _parent, _id, _div, _mode)\
+       {                                               \
+               .name      = _name,                     \
+               .lookup    = {                          \
+                       .dev_id    = _dev,              \
+                       .con_id    = _con,              \
+               },                                      \
+               .ops = &tegra_clk_shared_connector_ops, \
+               .parent = _parent,                      \
+               .u.shared_bus_user = {                  \
+                       .client_id = _id,               \
+                       .client_div = _div,             \
+                       .mode = _mode,                  \
+               },                                      \
+       }
 #define SHARED_EMC_CLK(_name, _dev, _con, _parent, _id, _div, _mode, _flag)\
        {                                               \
                .name      = _name,                     \
@@ -7260,6 +7318,18 @@ struct clk tegra_list_clks[] = {
 #endif
 };
 
+/* VI, ISP buses */
+static struct clk tegra_visp_clks[] = {
+       SHARED_CONNECT("vi.c4bus",      "vi.c4bus",     NULL,   &tegra_clk_c4bus,   "vi",    0, 0),
+       SHARED_CONNECT("isp.c4bus",     "isp.c4bus",    NULL,   &tegra_clk_c4bus,   "isp",   0, 0),
+       SHARED_CLK("override.c4bus",    "override.c4bus", NULL, &tegra_clk_c4bus,    NULL,   0, SHARED_OVERRIDE),
+
+       SHARED_CLK("via.vi.c4bus",      "via.vi",       NULL,   &tegra_visp_clks[0], NULL,   0, 0),
+       SHARED_CLK("vib.vi.c4bus",      "vib.vi",       NULL,   &tegra_visp_clks[0], NULL,   0, 0),
+
+       SHARED_CLK("ispa.isp.c4bus",    "ispa.isp",     NULL,   &tegra_visp_clks[1], "ispa", 0, 0),
+       SHARED_CLK("ispb.isp.c4bus",    "ispb.isp",     NULL,   &tegra_visp_clks[1], "ispb", 0, 0),
+};
 
 /* XUSB clocks */
 #define XUSB_ID "tegra-xhci"
@@ -7405,11 +7475,10 @@ struct clk_duplicate tegra_clk_duplicates[] = {
        CLK_DUPLICATE("actmon", "tegra_host1x", "actmon"),
        CLK_DUPLICATE("gpu", "tegra_gk20a", "PLLG_ref"),
        CLK_DUPLICATE("pll_p_out5", "tegra_gk20a", "pwr"),
-       CLK_DUPLICATE("isp", "tegra_isp", "isp"),
-       CLK_DUPLICATE("isp", "tegra_isp.1", "isp"),
-       CLK_DUPLICATE("ispb", "tegra_isp.1", "ispb"),
-       CLK_DUPLICATE("vi", "tegra_vi", "vi"),
-       CLK_DUPLICATE("vi", "tegra_vi.1", "vi"),
+       CLK_DUPLICATE("ispa.isp.c4bus", "tegra_isp", "isp"),
+       CLK_DUPLICATE("ispb.isp.c4bus", "tegra_isp.1", "isp"),
+       CLK_DUPLICATE("via.vi.c4bus", "tegra_vi", "vi"),
+       CLK_DUPLICATE("vib.vi.c4bus", "tegra_vi.1", "vi"),
        CLK_DUPLICATE("csi", "tegra_vi", "csi"),
        CLK_DUPLICATE("csi", "tegra_vi.1", "csi"),
        CLK_DUPLICATE("csus", "tegra_vi", "csus"),
@@ -7488,6 +7557,7 @@ struct clk *tegra_ptr_clks[] = {
 #endif
        &tegra_clk_gpu,
        &tegra_clk_isp,
+       &tegra_clk_c4bus,
 };
 
 struct clk *tegra_ptr_camera_mclks[] = {
@@ -8176,6 +8246,9 @@ void __init tegra12x_init_clocks(void)
        for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
                tegra12_init_one_clock(&tegra_list_clks[i]);
 
+       for (i = 0; i < ARRAY_SIZE(tegra_visp_clks); i++)
+               tegra12_init_one_clock(&tegra_visp_clks[i]);
+
        for (i = 0; i < ARRAY_SIZE(tegra_ptr_camera_mclks); i++)
                tegra12_init_one_clock(tegra_ptr_camera_mclks[i]);
 
index 0f01b72..4b549c6 100644 (file)
@@ -231,6 +231,7 @@ static struct dvfs core_dvfs_table[] = {
 #else
        CORE_DVFS("cbus",   -1, -1, 1, KHZ,   120000, 144000, 168000, 216000,  372000),
 #endif
+       CORE_DVFS("c4bus",  -1, -1, 1, KHZ,   120000, 156000, 182000, 312000,  444000),
 
        CORE_DVFS("pll_m",  -1, -1, 1, KHZ,   800000, 800000, 1066000, 1066000, 1066000),
        CORE_DVFS("pll_c",  -1, -1, 1, KHZ,   800000, 800000, 1066000, 1066000, 1066000),
index a5ab98d..4c3ac18 100644 (file)
@@ -196,9 +196,7 @@ struct nvhost_device_data t124_ispb_info = {
        .can_powergate   = false,
        .clockgate_delay = ISP_CLOCKGATE_DELAY,
        .powergate_delay = ISP_POWERGATE_DELAY,
-       .clocks          = {
-               {"isp", UINT_MAX},
-               {"ispb", 0} }
+       .clocks          = { {"isp", UINT_MAX} }
 };
 
 static struct platform_device tegra_isp01b_device = {