// SPDX-License-Identifier: GPL-2.0 or MIT
/*
* Copyright (C) 2016 Noralf Trønnes
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/io.h>
#include <linux/iosys-map.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <drm/drm_device.h>
#include <drm/drm_format_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_print.h>
#include <drm/drm_rect.h>
/**
* drm_format_conv_state_init - Initialize format-conversion state
* @state: The state to initialize
*
* Clears all fields in struct drm_format_conv_state. The state will
* be empty with no preallocated resources.
*/
void drm_format_conv_state_init(struct drm_format_conv_state *state)
{
state->tmp.mem = NULL;
state->tmp.size = 0;
state->tmp.preallocated = false;
}
EXPORT_SYMBOL(drm_format_conv_state_init);
/**
* drm_format_conv_state_copy - Copy format-conversion state
* @state: Destination state
* @old_state: Source state
*
* Copies format-conversion state from @old_state to @state; except for
* temporary storage.
*/
void drm_format_conv_state_copy(struct drm_format_conv_state *state,
const struct drm_format_conv_state *old_state)
{
/*
* So far, there's only temporary storage here, which we don't
* duplicate. Just clear the fields.
*/
state->tmp.mem = NULL;
state->tmp.size = 0;
state->tmp.preallocated = false;
}
EXPORT_SYMBOL(drm_format_conv_state_copy);
/**
* drm_format_conv_state_reserve - Allocates storage for format conversion
* @state: The format-conversion state
* @new_size: The minimum allocation size
* @flags: Flags for kmalloc()
*
* Allocates at least @new_size bytes and returns a pointer to the memory
* range. After calling this function, previously returned memory blocks
* are invalid. It's best to collect all memory requirements of a format
* conversion and call this function once to allocate the range.
*
* Returns:
* A pointer to the allocated memory range, or NULL otherwise.
*/
void *drm_format_conv_state_reserve(struct drm_format_conv_state *state,
size_t new_size, gfp_t flags)
{
void *mem;
if (new_size <= state->tmp.size)
goto out;
else if (state->tmp.preallocated)
return NULL;
mem = krealloc(state->tmp.mem, new_size, flags);
if (!mem)
return NULL;
state->tmp.mem = mem;
state->tmp.size = new_size;
out:
return state->tmp.mem;
}
EXPORT_SYMBOL(drm_format_conv_state_reserve);
/**
* drm_format_conv_state_release - Releases an format-conversion storage
* @state: The format-conversion state
*
* Releases the memory range references by the format-conversion state.
* After this call, all pointers to the memory are invalid. Prefer
* drm_format_conv_state_init() for cleaning up and unloading a driver.
*/
void drm_format_conv_state_release(struct drm_format_conv_state *state)
{
if (state->tmp.preallocated)
return;
kfree(state->tmp.mem);
state->tmp.mem = NULL;
state->tmp.size = 0;
}
EXPORT_SYMBOL(drm_format_conv_state_release);
static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp)
{
return clip->y1 * pitch + clip->x1 * cpp;
}
/**
* drm_fb_clip_offset - Returns the clipping rectangles byte-offset in a framebuffer
* @pitch: Framebuffer line pitch in byte
* @f