linux/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20 * DEALINGS IN THE SOFTWARE.
  21 */
  22#include "priv.h"
  23
  24#include <core/msgqueue.h>
  25#include <subdev/top.h>
  26#include <engine/falcon.h>
  27
  28static void *
  29nvkm_sec2_dtor(struct nvkm_engine *engine)
  30{
  31        struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
  32        nvkm_msgqueue_del(&sec2->queue);
  33        nvkm_falcon_del(&sec2->falcon);
  34        return sec2;
  35}
  36
  37static void
  38nvkm_sec2_intr(struct nvkm_engine *engine)
  39{
  40        struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
  41        struct nvkm_subdev *subdev = &engine->subdev;
  42        struct nvkm_device *device = subdev->device;
  43        u32 disp = nvkm_rd32(device, sec2->addr + 0x01c);
  44        u32 intr = nvkm_rd32(device, sec2->addr + 0x008) & disp & ~(disp >> 16);
  45
  46        if (intr & 0x00000040) {
  47                schedule_work(&sec2->work);
  48                nvkm_wr32(device, sec2->addr + 0x004, 0x00000040);
  49                intr &= ~0x00000040;
  50        }
  51
  52        if (intr) {
  53                nvkm_error(subdev, "unhandled intr %08x\n", intr);
  54                nvkm_wr32(device, sec2->addr + 0x004, intr);
  55
  56        }
  57}
  58
  59static void
  60nvkm_sec2_recv(struct work_struct *work)
  61{
  62        struct nvkm_sec2 *sec2 = container_of(work, typeof(*sec2), work);
  63
  64        if (!sec2->queue) {
  65                nvkm_warn(&sec2->engine.subdev,
  66                          "recv function called while no firmware set!\n");
  67                return;
  68        }
  69
  70        nvkm_msgqueue_recv(sec2->queue);
  71}
  72
  73
  74static int
  75nvkm_sec2_oneinit(struct nvkm_engine *engine)
  76{
  77        struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
  78        struct nvkm_subdev *subdev = &sec2->engine.subdev;
  79
  80        if (!sec2->addr) {
  81                sec2->addr = nvkm_top_addr(subdev->device, subdev->index);
  82                if (WARN_ON(!sec2->addr))
  83                        return -EINVAL;
  84        }
  85
  86        return nvkm_falcon_v1_new(subdev, "SEC2", sec2->addr, &sec2->falcon);
  87}
  88
  89static int
  90nvkm_sec2_fini(struct nvkm_engine *engine, bool suspend)
  91{
  92        struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
  93        flush_work(&sec2->work);
  94        return 0;
  95}
  96
  97static const struct nvkm_engine_func
  98nvkm_sec2 = {
  99        .dtor = nvkm_sec2_dtor,
 100        .oneinit = nvkm_sec2_oneinit,
 101        .fini = nvkm_sec2_fini,
 102        .intr = nvkm_sec2_intr,
 103};
 104
 105int
 106nvkm_sec2_new_(struct nvkm_device *device, int index, u32 addr,
 107               struct nvkm_sec2 **psec2)
 108{
 109        struct nvkm_sec2 *sec2;
 110
 111        if (!(sec2 = *psec2 = kzalloc(sizeof(*sec2), GFP_KERNEL)))
 112                return -ENOMEM;
 113        sec2->addr = addr;
 114        INIT_WORK(&sec2->work, nvkm_sec2_recv);
 115
 116        return nvkm_engine_ctor(&nvkm_sec2, device, index, true, &sec2->engine);
 117};
 118