gk20a: Moved bind fecs to init_gr_support
[linux-3.10.git] / drivers / gpu / nvgpu / gk20a / pmu_gk20a.c
index 21e4d61..f3d6e00 100644 (file)
@@ -3,7 +3,7 @@
  *
  * GK20A PMU (aka. gPMU outside gk20a context)
  *
- * Copyright (c) 2011-2014, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2011-2015, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -47,6 +47,8 @@ static void ap_callback_init_and_enable_ctrl(
 static int gk20a_pmu_ap_send_command(struct gk20a *g,
                        union pmu_ap_cmd *p_ap_cmd, bool b_block);
 
+static int pmu_init_powergating(struct gk20a *g);
+
 static u32 pmu_cmdline_size_v0(struct pmu_gk20a *pmu)
 {
        return sizeof(struct pmu_cmdline_args_v0);
@@ -1735,12 +1737,13 @@ static void pmu_handle_pg_buf_config_msg(struct gk20a *g, struct pmu_msg *msg,
                return;
        }
 
-       if (eng_buf_stat->status == PMU_PG_MSG_ENG_BUF_FAILED) {
-               gk20a_err(dev_from_gk20a(g), "failed to load PGENG buffer");
-       }
-
        pmu->buf_loaded = (eng_buf_stat->status == PMU_PG_MSG_ENG_BUF_LOADED);
-       schedule_work(&pmu->pg_init);
+       if ((!pmu->buf_loaded) &&
+               (pmu->pmu_state == PMU_STATE_LOADING_PG_BUF))
+                       gk20a_err(dev_from_gk20a(g), "failed to load PGENG buffer");
+       else {
+               schedule_work(&pmu->pg_init);
+       }
 }
 
 int gk20a_init_pmu_setup_hw1(struct gk20a *g)
@@ -1792,9 +1795,13 @@ static void pmu_setup_hw(struct work_struct *work)
        struct gk20a *g = pmu->g;
 
        switch (pmu->pmu_state) {
+       case PMU_STATE_INIT_RECEIVED:
+               gk20a_dbg_pmu("pmu starting");
+               pmu_init_powergating(g);
+               break;
        case PMU_STATE_ELPG_BOOTED:
                gk20a_dbg_pmu("elpg booted");
-               gk20a_init_pmu_bind_fecs(g);
+               gk20a_init_pmu_load_fecs(g);
                break;
        case PMU_STATE_LOADING_PG_BUF:
                gk20a_dbg_pmu("loaded pg buf");
@@ -1813,79 +1820,14 @@ static void pmu_setup_hw(struct work_struct *work)
        }
 }
 
-int gk20a_init_pmu_bind_fecs(struct gk20a *g)
+int gk20a_init_pmu_load_fecs(struct gk20a *g)
 {
        struct pmu_gk20a *pmu = &g->pmu;
-       struct mm_gk20a *mm = &g->mm;
-       struct vm_gk20a *vm = &mm->pmu.vm;
-       struct device *d = dev_from_gk20a(g);
        struct pmu_cmd cmd;
        u32 desc;
-       int err;
-       u32 size;
-       struct sg_table *sgt_pg_buf;
-       dma_addr_t iova;
-
+       int err = 0;
        gk20a_dbg_fn("");
 
-       size = 0;
-       gk20a_gr_wait_initialized(g);
-       err = gr_gk20a_fecs_get_reglist_img_size(g, &size);
-       if (err) {
-               gk20a_err(dev_from_gk20a(g),
-                       "fail to query fecs pg buffer size");
-               return err;
-       }
-
-       if (!pmu->pg_buf.cpuva) {
-               pmu->pg_buf.cpuva = dma_alloc_coherent(d, size,
-                                               &iova,
-                                               GFP_KERNEL);
-               if (!pmu->pg_buf.cpuva) {
-                       gk20a_err(d, "failed to allocate memory\n");
-                       return -ENOMEM;
-               }
-
-               pmu->pg_buf.iova = iova;
-               pmu->pg_buf.size = size;
-
-               err = gk20a_get_sgtable(d, &sgt_pg_buf,
-                                       pmu->pg_buf.cpuva,
-                                       pmu->pg_buf.iova,
-                                       size);
-               if (err) {
-                       gk20a_err(d, "failed to create sg table\n");
-                       goto err_free_pg_buf;
-               }
-
-               pmu->pg_buf.pmu_va = gk20a_gmmu_map(vm,
-                                       &sgt_pg_buf,
-                                       size,
-                                       0, /* flags */
-                                       gk20a_mem_flag_none);
-               if (!pmu->pg_buf.pmu_va) {
-                       gk20a_err(d, "failed to map fecs pg buffer");
-                       err = -ENOMEM;
-                       goto err_free_sgtable;
-               }
-
-               gk20a_free_sgtable(&sgt_pg_buf);
-       }
-
-       err = gr_gk20a_fecs_set_reglist_bind_inst(g, mm->pmu.inst_block.cpu_pa);
-       if (err) {
-               gk20a_err(dev_from_gk20a(g),
-                       "fail to bind pmu inst to gr");
-               return err;
-       }
-
-       err = gr_gk20a_fecs_set_reglist_virtual_addr(g, pmu->pg_buf.pmu_va);
-       if (err) {
-               gk20a_err(dev_from_gk20a(g),
-                       "fail to set pg buffer pmu va");
-               return err;
-       }
-
        memset(&cmd, 0, sizeof(struct pmu_cmd));
        cmd.hdr.unit_id = PMU_UNIT_PG;
        cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_eng_buf_load);
@@ -1903,15 +1845,6 @@ int gk20a_init_pmu_bind_fecs(struct gk20a *g)
                        pmu_handle_pg_buf_config_msg, pmu, &desc, ~0);
        pmu->pmu_state = PMU_STATE_LOADING_PG_BUF;
        return err;
-
-err_free_sgtable:
-       gk20a_free_sgtable(&sgt_pg_buf);
-err_free_pg_buf:
-       dma_free_coherent(d, size,
-               pmu->pg_buf.cpuva, pmu->pg_buf.iova);
-       pmu->pg_buf.cpuva = NULL;
-       pmu->pg_buf.iova = 0;
-       return err;
 }
 
 static void pmu_setup_hw_load_zbc(struct gk20a *g)
@@ -1967,6 +1900,8 @@ static void pmu_setup_hw_enable_elpg(struct gk20a *g)
                gk20a_aelpg_init(g);
                gk20a_aelpg_init_and_enable(g, PMU_AP_CTRL_ID_GRAPHICS);
        }
+
+       wake_up(&g->pmu.boot_wq);
 }
 
 int gk20a_init_pmu_support(struct gk20a *g)
@@ -1993,6 +1928,8 @@ int gk20a_init_pmu_support(struct gk20a *g)
                err = gk20a_init_pmu_setup_hw1(g);
                if (err)
                        return err;
+
+               pmu->pmu_state = PMU_STATE_STARTING;
        }
 
        return err;
@@ -2023,9 +1960,10 @@ static void pmu_handle_pg_elpg_msg(struct gk20a *g, struct pmu_msg *msg,
        case PMU_PG_ELPG_MSG_DISALLOW_ACK:
                gk20a_dbg_pmu("DISALLOW is acknowledged from PMU");
                pmu->elpg_stat = PMU_ELPG_STAT_OFF;
-               if (pmu->pmu_state == PMU_STATE_STARTING)
+               if (pmu->pmu_state == PMU_STATE_ELPG_BOOTING) {
                        pmu->pmu_state = PMU_STATE_ELPG_BOOTED;
-               schedule_work(&pmu->pg_init);
+                       schedule_work(&pmu->pg_init);
+               }
                break;
        default:
                gk20a_err(dev_from_gk20a(g),
@@ -2058,14 +1996,16 @@ static void pmu_handle_pg_stat_msg(struct gk20a *g, struct pmu_msg *msg,
        }
 }
 
-static int pmu_init_powergating(struct pmu_gk20a *pmu)
+static int pmu_init_powergating(struct gk20a *g)
 {
-       struct gk20a *g = pmu->g;
+       struct pmu_gk20a *pmu = &g->pmu;
        struct pmu_cmd cmd;
        u32 seq;
 
        gk20a_dbg_fn("");
 
+       mutex_lock(&pmu->isr_mutex);
+
        if (tegra_cpu_is_asim()) {
                /* TBD: calculate threshold for silicon */
                gk20a_writel(g, pwr_pmu_pg_idlefilth_r(ENGINE_GR_GK20A),
@@ -2080,6 +2020,8 @@ static int pmu_init_powergating(struct pmu_gk20a *pmu)
                                PMU_PG_POST_POWERUP_IDLE_THRESHOLD);
        }
 
+       gk20a_gr_wait_initialized(g);
+
        /* init ELPG */
        memset(&cmd, 0, sizeof(struct pmu_cmd));
        cmd.hdr.unit_id = PMU_UNIT_PG;
@@ -2120,7 +2062,13 @@ static int pmu_init_powergating(struct pmu_gk20a *pmu)
        gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
                        pmu_handle_pg_elpg_msg, pmu, &seq, ~0);
 
-       pmu->pmu_state = PMU_STATE_STARTING;
+       /* start with elpg disabled until first enable call */
+       pmu->elpg_refcnt = 0;
+
+       if (pmu->pmu_state == PMU_STATE_INIT_RECEIVED)
+               pmu->pmu_state = PMU_STATE_ELPG_BOOTING;
+
+       mutex_unlock(&pmu->isr_mutex);
 
        return 0;
 }
@@ -2235,6 +2183,7 @@ static int pmu_process_init_msg(struct pmu_gk20a *pmu,
        union pmu_init_msg_pmu *init;
        struct pmu_sha1_gid_data gid_data;
        u32 i, tail = 0;
+       gk20a_dbg_pmu("init received\n");
 
        tail = pwr_pmu_msgq_tail_val_v(
                gk20a_readl(g, pwr_pmu_msgq_tail_r()));
@@ -2292,6 +2241,9 @@ static int pmu_process_init_msg(struct pmu_gk20a *pmu,
                                PMU_DMEM_ALLOC_ALIGNMENT);
 
        pmu->pmu_ready = true;
+       pmu->pmu_state = PMU_STATE_INIT_RECEIVED;
+       schedule_work(&pmu->pg_init);
+       gk20a_dbg_pmu("init received end\n");
 
        return 0;
 }
@@ -2622,7 +2574,6 @@ static int pmu_process_message(struct pmu_gk20a *pmu)
 
        if (unlikely(!pmu->pmu_ready)) {
                pmu_process_init_msg(pmu, &msg);
-               pmu_init_powergating(pmu);
                pmu_init_perfmon(pmu);
                return 0;
        }
@@ -2889,7 +2840,8 @@ void gk20a_pmu_isr(struct gk20a *g)
 
        gk20a_dbg_pmu("received falcon interrupt: 0x%08x", intr);
 
-       if (!intr) {
+       if (!intr || pmu->pmu_state == PMU_STATE_OFF) {
+               gk20a_writel(g, pwr_falcon_irqsclr_r(), intr);
                mutex_unlock(&pmu->isr_mutex);
                mutex_unlock(&pmu->isr_enable_lock);
                return;