+static void transfer_tile(struct bo *bo, uint8_t *tiled, uint8_t *untiled, enum tegra_map_type type,
+ uint32_t bytes_per_pixel, uint32_t gob_top, uint32_t gob_left,
+ uint32_t gob_size_pixels, uint8_t *tiled_last)
+{
+ uint8_t *tmp;
+ uint32_t x, y, k;
+ for (k = 0; k < gob_size_pixels; k++) {
+ /*
+ * Given the kth pixel starting from the tile specified by
+ * gob_top and gob_left, unswizzle to get the standard (x, y)
+ * representation.
+ */
+ x = gob_left + (((k >> 3) & 8) | ((k >> 1) & 4) | (k & 3));
+ y = gob_top + ((k >> 7 << 3) | ((k >> 3) & 6) | ((k >> 2) & 1));
+
+ if (tiled >= tiled_last)
+ return;
+
+ if (x >= bo->width || y >= bo->height) {
+ tiled += bytes_per_pixel;
+ continue;
+ }
+
+ tmp = untiled + y * bo->strides[0] + x * bytes_per_pixel;
+
+ if (type == TEGRA_READ_TILED_BUFFER)
+ memcpy(tmp, tiled, bytes_per_pixel);
+ else if (type == TEGRA_WRITE_TILED_BUFFER)
+ memcpy(tiled, tmp, bytes_per_pixel);
+
+ /* Move on to next pixel. */
+ tiled += bytes_per_pixel;
+ }
+}
+
+static void transfer_tiled_memory(struct bo *bo, uint8_t *tiled, uint8_t *untiled,
+ enum tegra_map_type type)
+{
+ uint32_t gob_width, gob_height, gob_size_bytes, gob_size_pixels, gob_count_x, gob_count_y,
+ gob_top, gob_left;
+ uint32_t i, j, offset;
+ uint8_t *tmp, *tiled_last;
+ uint32_t bytes_per_pixel = drv_stride_from_format(bo->format, 1, 0);
+
+ /*
+ * The blocklinear format consists of 8*(2^n) x 64 byte sized tiles,
+ * where 0 <= n <= 4.
+ */
+ gob_width = DIV_ROUND_UP(NV_BLOCKLINEAR_GOB_WIDTH, bytes_per_pixel);
+ gob_height = NV_BLOCKLINEAR_GOB_HEIGHT * (1 << NV_DEFAULT_BLOCK_HEIGHT_LOG2);
+ /* Calculate the height from maximum possible gob height */
+ while (gob_height > NV_BLOCKLINEAR_GOB_HEIGHT && gob_height >= 2 * bo->height)
+ gob_height /= 2;
+
+ gob_size_bytes = gob_height * NV_BLOCKLINEAR_GOB_WIDTH;
+ gob_size_pixels = gob_height * gob_width;
+
+ gob_count_x = DIV_ROUND_UP(bo->strides[0], NV_BLOCKLINEAR_GOB_WIDTH);
+ gob_count_y = DIV_ROUND_UP(bo->height, gob_height);
+
+ tiled_last = tiled + bo->total_size;
+
+ offset = 0;
+ for (j = 0; j < gob_count_y; j++) {
+ gob_top = j * gob_height;
+ for (i = 0; i < gob_count_x; i++) {
+ tmp = tiled + offset;
+ gob_left = i * gob_width;
+
+ transfer_tile(bo, tmp, untiled, type, bytes_per_pixel, gob_top, gob_left,
+ gob_size_pixels, tiled_last);
+
+ offset += gob_size_bytes;
+ }
+ }
+}
+
+static int tegra_init(struct driver *drv)
+{
+ int ret;
+ struct format_metadata metadata;
+ uint64_t flags = BO_USE_RENDER_MASK;
+
+ metadata.tiling = NV_MEM_KIND_PITCH;
+ metadata.priority = 1;
+ metadata.modifier = DRM_FORMAT_MOD_NONE;
+
+ ret = drv_add_combinations(drv, render_target_formats, ARRAY_SIZE(render_target_formats),
+ &metadata, flags);
+ if (ret)
+ return ret;
+
+ drv_modify_combination(drv, DRM_FORMAT_XRGB8888, &metadata, BO_USE_CURSOR | BO_USE_SCANOUT);
+ drv_modify_combination(drv, DRM_FORMAT_ARGB8888, &metadata, BO_USE_CURSOR | BO_USE_SCANOUT);
+
+ flags &= ~BO_USE_SW_WRITE_OFTEN;
+ flags &= ~BO_USE_SW_READ_OFTEN;
+ flags &= ~BO_USE_LINEAR;
+
+ metadata.tiling = NV_MEM_KIND_C32_2CRA;
+ metadata.priority = 2;
+
+ ret = drv_add_combinations(drv, render_target_formats, ARRAY_SIZE(render_target_formats),
+ &metadata, flags);
+ if (ret)
+ return ret;
+
+ drv_modify_combination(drv, DRM_FORMAT_XRGB8888, &metadata, BO_USE_SCANOUT);
+ drv_modify_combination(drv, DRM_FORMAT_ARGB8888, &metadata, BO_USE_SCANOUT);
+ return 0;
+}
+
+static int tegra_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
+ uint32_t flags)